Денормализация и дублирование

Почему в документной БД дублировать данные иногда правильно — и какова за это плата.

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

В SQL дублирование — грех, в Mongo — инструмент

Реляционная нормализация борется с дублированием: каждый факт хранится в одном месте. Цена — JOIN при каждом чтении. В документной модели чтения часто важнее, поэтому небольшое дублирование данных, которые редко меняются, — допустимый и распространённый приём.

Пример: имя автора в посте

У поста есть автор. Можно хранить только authorId и подтягивать имя отдельным запросом. Но лента постов показывает имя автора всегда — значит, выгодно продублировать его прямо в посте:

{
  "_id": "p1",
  "title": "Заметки о Mongo",
  "authorId": "u1",
  "authorName": "Анна"
}

Теперь лента рисуется одним запросом к posts, без обращения к users. На больших объёмах это огромная экономия.

Плата: рассинхрон при изменении

У дублирования есть обратная сторона. Если пользователь сменит имя, продублированное authorName в постах не обновится само — придётся пройтись по постам:

db.posts.updateMany(
  { authorId: "u1" },
  { $set: { authorName: "Анна Петрова" } }
)

Поэтому денормализуют именно редко меняющиеся данные. Имя пользователя меняется раз в годы — дублировать безопасно. Баланс на счёте меняется постоянно — дублировать нельзя.

Когда денормализация оправдана

  • Чтений намного больше, чем записей. Ленты, каталоги, карточки — оптимизируем под чтение.
  • Дублируемые данные стабильны. Имя, заголовок, категория — а не цена и остаток.
  • JOIN на каждом чтении дорог. Денормализация убирает $lookup из горячего пути.

Когда не стоит

Если данные меняются часто или должны быть всегда абсолютно точны (финансы, остатки склада в реальном времени), дублирование создаёт риск рассогласования. Тогда лучше ссылка и явный $lookup. И главное — не дублируйте «на всякий случай»: денормализация оправдана конкретным частым запросом, а не абстрактным «вдруг пригодится».

Итог

  • Денормализация ускоряет чтение, убирая необходимость объединять коллекции.
  • Плата — ручная синхронизация дубля при изменении исходных данных.
  • Дублируйте редко меняющиеся данные и только под реальный частый запрос.
Проверьте себя
1. Что такое денормализация в MongoDB?
AЗапрет на любое дублирование данных
BОсознанное дублирование данных ради ускорения чтения
CАвтоматическое объединение коллекций
DУдаление лишних полей
2. Какие данные безопаснее всего денормализовать (дублировать)?
AЧасто меняющиеся, например остаток на складе
BРедко меняющиеся, например имя автора или название категории
CСлучайные значения
DПоля _id
3. Какова основная плата за денормализацию?
AЗамедление всех запросов
BНеобходимость вручную синхронизировать дубли при изменении исходных данных
CПотеря поля _id
DНевозможность удалять документы
Поддержать проект