Что такое денормализация базы данных и когда её применяют?

«Что такое денормализация базы данных и когда её применяют?» — вопрос из категории Базы данных, который задают на 35% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Денормализация — это сознательное отступление от правил нормализации базы данных путём введения контролируемой избыточности данных с целью оптимизации производительности операций чтения.

Зачем это нужно? Нормализованная база (без дублирования) минимизирует аномалии обновления, но часто требует выполнения множества операций 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), если бизнес это допускает.
  • Увеличение размера и сложности обновления:
    • Решение: Чётко взвешивать выгоду от скорости чтения и дополнительные затраты на запись. Часто денормализуют только самые критичные для производительности запросы.