Индексы и денормализация

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

Индекс — вспомогательная структура (обычно B-дерево), которая позволяет находить строки по значению поля, не просматривая всю таблицу.

Как работает индекс

Без индекса поиск WHERE email = 'x' заставляет базу прочитать все строки (full scan) — O(N). Индекс по email хранит отсортированную структуру, по которой нужная строка находится за O(log N). На миллионах строк это разница между «мгновенно» и «секунды».

CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = '[email protected]';

Цена индекса

Индекс — не бесплатный. У него есть обратная сторона, которую часто забывают:

ПлюсМинус
Чтение по полю — O(log N)Каждая запись/обновление дороже: надо обновить и индексы
Быстрый ORDER BY по полюИндекс занимает место на диске
Ускоряет JOIN по ключуЛишние индексы тормозят INSERT/UPDATE

Правило: индексируйте поля, по которым часто ищете и сортируете, но не всё подряд. На таблице с интенсивной записью лишние индексы — это налог на каждую вставку.

Нормализация

Нормализация — хранить каждый факт ровно один раз, разнося данные по связанным таблицам. Имя пользователя лежит в users, а в orders — только user_id. Плюс: нет дублей, обновил имя в одном месте. Минус: чтобы показать заказ с именем покупателя, нужен JOIN, а JOIN'ы дороги под большой нагрузкой и плохо переживают шардирование.

Денормализация

Денормализация — осознанно продублировать данные, чтобы избежать JOIN при чтении. Например, прямо в orders хранить user_name. Тогда показать заказ — одна выборка без JOIN.

КритерийНормализацияДенормализация
Дублированиенетесть (намеренное)
Чтениемедленнее (JOIN)быстрее (одна выборка)
Записьпроще, один источник правдысложнее: обновлять копии
Рискнизкийрассинхрон копий

Когда денормализовать

Когда чтений много, они в горячем пути, а данные меняются редко. Лента соцсети — классика: имя и аватар автора дублируют в каждый пост, потому что лента читается миллионы раз, а имя меняется раз в год. Это прямой компромисс: быстрее читать ценой более сложной записи и риска рассинхрона. В NoSQL денормализация — норма жизни, ведь JOIN там обычно нет.

Итог

  • Индекс ускоряет чтение по полю (O(log N)), но удорожает запись и занимает место.
  • Нормализация хранит факт один раз (нет дублей), но требует JOIN при чтении.
  • Денормализация дублирует данные ради быстрого чтения ценой сложной записи и риска рассинхрона.
Проверьте себя
1. Что индекс ускоряет и за счёт чего?
AЗапись, за счёт чтения
BЧтение по полю (O(log N) вместо full scan), но удорожает запись и занимает место
CИ чтение, и запись бесплатно
DТолько удаление строк
2. Когда денормализация (дублирование данных) оправдана?
AКогда записей намного больше, чем чтений
BКогда чтений много, они в горячем пути, а данные меняются редко
CВсегда, дубли только помогают
DКогда нужна максимальная экономия места
3. Главный риск денормализации — это…
Aпотеря индекса
Bрассинхронизация дублированных копий данных
Cневозможность чтения
Dзамедление чтения
Поддержать проект