Ответ
Денормализация — это сознательное отступление от правил нормализации базы данных путём введения контролируемой избыточности данных с целью оптимизации производительности операций чтения.
Зачем это нужно? Нормализованная база (без дублирования) минимизирует аномалии обновления, но часто требует выполнения множества операций JOIN для получения нужных данных. На системах с высокой нагрузкой на чтение (например, отчёты, аналитические панели, ленты новостей) эти JOIN становятся узким местом. Денормализация жертвует некоторой целостностью данных и увеличивает объём хранилища ради скорости выборки.
Типичный пример:
-- НОРМАЛИЗОВАННАЯ СХЕМА (3NF)
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT REFERENCES users(id),
total_amount DECIMAL(10,2),
created_at TIMESTAMP
);
-- Чтобы получить отчёт "Имя пользователя + сумма его заказа", нужен JOIN:
SELECT u.username, o.total_amount, o.created_at
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.created_at > '2023-01-01';
-- ДЕНОРМАЛИЗОВАННАЯ СХЕМА
-- Добавляем избыточное поле username прямо в таблицу orders
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
username VARCHAR(50), -- Дублируем данные из users
total_amount DECIMAL(10,2),
created_at TIMESTAMP
);
-- Теперь тот же отчёт выполняется без JOIN, что может быть в разы быстрее:
SELECT username, total_amount, created_at
FROM orders
WHERE created_at > '2023-01-01';
Когда применять денормализацию:
- Системы OLAP (Analytical Processing): Хранилища данных, дашборды, где данные обновляются редко (раз в сутки/неделю), но запросы на чтение сложные и частые.
- Микросервисная архитектура: Когда данные из одного сервиса (например,
user-service) часто нужны в другом (order-service), и вызов API между сервисами дороже, чем дублирование. - Кэширование в БД: Создание материализованных представлений или summary-таблиц, которые предрассчитывают агрегаты.
- Высоконагруженные read-heavy приложения: Социальные сети, медиа-платформы.
Риски и как с ними бороться:
- Несогласованность данных: Если имя пользователя изменится в
users, оно останется старым в денормализованном полеorders.username.- Решение: Обновлять данные асинхронно (через события, очереди), либо смириться с некоторой задержкой в согласованности (eventual consistency), если бизнес это допускает.
- Увеличение размера и сложности обновления:
- Решение: Чётко взвешивать выгоду от скорости чтения и дополнительные затраты на запись. Часто денормализуют только самые критичные для производительности запросы.