Как используется денормализация базы данных и для чего она нужна?
Что проверяют
Понимаете ли вы, что денормализация это осознанная избыточность ради чтения, и кто в системе отвечает за согласованность копий. Следом обычно спрашивают, как вы будете поддерживать дублированное поле актуальным и что будет при гонке.
Как отвечать
Сначала определение: нормализованная схема хранит каждый факт в одном месте, денормализация добавляет копии или предрасчитанные значения, чтобы убрать дорогие JOIN и агрегаты из горячих запросов. Цена: запись усложняется, копии могут разойтись.
Типовые приёмы:
- счётчики:
comments_countу поста вместоCOUNT(*)на каждый показ. В Django обновляют атомарно черезF("comments_count") + 1, иначе два параллельных запроса потеряют инкремент; - копия поля: цена и название товара в строке заказа. Часто это требование, а не оптимизация: заказ должен помнить цену на момент покупки;
- материализованные представления:
CREATE MATERIALIZED VIEWв PostgreSQL для отчётов, обновление черезREFRESH MATERIALIZED VIEW CONCURRENTLY, которому нужен уникальный индекс; - JSONB: теги и атрибуты прямо в строке, если их читают вместе с ней;
- витрины: широкие таблицы в ClickHouse или хранилище, собранные ETL из нормализованной OLTP-базы.
Затем скажите, кто поддерживает копии: транзакция в приложении, триггер, периодический пересчёт или событие в очереди, и какое отставание допустимо. Правильный порядок: сначала индексы и EXPLAIN ANALYZE, select_related против N+1, кэш, и только если мало, денормализация.
Где спотыкаются
Обновляют копию через сигналы Django и забывают, что QuerySet.update() и bulk_create() сигнал post_save не отправляют. Счётчик тихо расходится с реальностью.
Выдают за денормализацию схему, где всё с самого начала свалено в одну таблицу. Денормализуют нормализованную модель по замерам, иначе это просто долг.
Не предусматривают способа починить расхождение: нет скрипта пересчёта и проверки. Копии рано или поздно разойдутся, это нужно уметь обнаружить.