Индексы и денормализация
Скорость чтения почти всегда покупается за счёт места, записи или дублирования данных.
Индекс — вспомогательная структура (обычно 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 при чтении.
- Денормализация дублирует данные ради быстрого чтения ценой сложной записи и риска рассинхрона.