Что такое нормализация базы данных (и когда стоит нарушать правила)?
У нормализации баз данных репутация академической темы, полной правил с солидными названиями — первая нормальная форма, вторая нормальная форма и так далее, — но идея, которая за ней стоит, приятно практична: организуйте данные так, чтобы один и тот же факт никогда не хранился в двух местах, потому что, как только это случится, эти два места рано или поздно разойдутся.
Какую проблему решает нормализация
Представьте таблицу, где в каждой строке вместе с заказом прямо хранятся полное имя и email клиента. Если клиент изменит email, придётся обновить все строки заказов, где он упоминается, — а пропустите хотя бы одну, и данные станут незаметно противоречивыми: в одной базе будут жить две разные «правды». Нормализация решает это так: данные клиента хранятся в одном месте (таблице клиентов), а везде, где они нужны, на них ссылаются по ID.
Нормальные формы без жаргона
- Первая нормальная форма: в каждом столбце хранится одно значение, а не список, втиснутый в одно поле. Столбец «phone_numbers» с тремя номерами через запятую нарушает это правило.
- Вторая нормальная форма: каждый неключевой столбец зависит от всего первичного ключа, а не от его части; в основном это касается таблиц с составными ключами.
- Третья нормальная форма: неключевые столбцы зависят только от ключа, а не друг от друга. Если город клиента можно определить по почтовому индексу, хранение и того и другого напрямую — приглашение к тому, что однажды они разойдутся.
На практике большинство хорошо спроектированных систем стремятся к третьей нормальной форме и на ней останавливаются. Всё, что дальше, в основном живёт в учебниках, а не в реальных продакшен-схемах.
Что даёт нормализация
Согласованные данные без дублирующихся фактов, которые могут случайно рассинхронизироваться; меньший объём хранения, поскольку одни и те же значения не повторяются в разных строках; более простые обновления — меняете факт в одном месте, и все ссылки на него автоматически отражают изменение.
Когда строгая нормализация начинает обходиться дорого
Обратная сторона — сложность запросов. Сильно нормализованные данные, разбросанные по множеству маленьких таблиц, часто означают объединение полудюжины таблиц ради ответа на простой вопрос, а у каждого объединения есть реальная цена с точки зрения производительности. Для систем с преобладанием чтения — дашбордов отчётности, аналитики, всего, где запросов на чтение гораздо больше, чем на запись, — эта цена может оказаться существенной.
Здесь и появляется намеренная денормализация: сознательное дублирование части данных, чтобы избежать дорогих объединений, в обмен на более быстрое чтение. Это законная и распространённая стратегия, а не изъян проектирования, — при условии, что это осознанный компромисс, а не случайность. Многие реальные системы нормализуют основные транзакционные данные, а затем поддерживают денормализованную, оптимизированную для чтения копию специально для отчётности или дашбордов.
Практический вывод
Нормализуйте по умолчанию, особенно там, где согласованность действительно важна, — деньги, складские остатки, всё, что ни в коем случае не должно незаметно противоречить самому себе. Денормализуйте осознанно и только там, где вы действительно измерили реальную проблему с производительностью, которую вызывают объединения. Если гадать об этом компромиссе в любую сторону, не измерив, схемы в итоге становятся либо такими, что по ним невозможно эффективно делать запросы, либо полными данных, которые незаметно рассинхронизировались. Найти правильный баланс для реальных сценариев чтения и записи конкретного продукта — основа нашей работы над заказным ПО и инфраструктурой.