← Назад к вопросам

Для чего используются денормализованные данные?

2.0 Middle🔥 131 комментариев
#Базы данных и SQL#Кэширование и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Назначение денормализованных данных

Денормализация — это намеренное нарушение правил нормальной формы в базе данных для повышения производительности. Вместо разбиения данных на множество таблиц с связями, мы храним редундантные данные в одном месте.

Основные причины использования

Производительность — главная мотивация. Нормализованные данные требуют множественных JOINов, которые замедляют запросы:

SELECT u.name, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
GROUP BY u.id;

При денормализации счётчик постов хранится прямо в таблице users, запрос становится мгновенным.

Когда использовать денормализацию

Часто читаемые данные — если данные постоянно читаются, но редко изменяются, дублирование оправдано.

Высоконагруженные системы — миллионы запросов в секунду требуют максимальной скорости. Каждый JOIN стоит дорого.

Аналитика и отчёты — денормализованные таблицы (data warehouse, OLAP) оптимальны для аналитики.

NoSQL документы — MongoDB, Firestore часто хранят вложенные структуры для удобства.

Проблемы денормализации

Консистентность — если данные дублируются, нужно обновлять их в нескольких местах. Ошибка приводит к рассинхронизации.

Сложность кода — больше логики на обновление данных.

Размер БД — дублирование увеличивает объём хранилища.

Практический пример

db.posts.insertOne({
  _id: ObjectId(),
  title: 'Node.js best practices',
  author: {
    id: ObjectId(),
    name: 'John Doe'
  },
  comments_count: 42
});

Когда меняется имя автора, нужно обновить ВСЕ посты этого автора.

Компромисс

Современный подход — кэширование (Redis). Данные остаются нормализованными в БД, но часто используемые комбинации кэшируются:

const userWithPosts = await redis.get('user:' + id + ':posts');
if (!userWithPosts) {
  userWithPosts = await db.query('SELECT FROM users JOIN posts');
  await redis.set('user:' + id + ':posts', userWithPosts, 3600);
}

Денормализация полезна в специфичных случаях, но требует тщательного планирования.

Для чего используются денормализованные данные? | PrepBro