Нормализация базы данных — 1NF, 2NF, 3NF простыми словами
Коротко
Нормализация — это процесс организации таблиц в базе данных так, чтобы данные не дублировались и не противоречили друг другу. На практике выделяют три основных нормальных формы: 1NF, 2NF, 3NF. Аналитику важно понимать нормализацию, чтобы разбираться в структуре продуктовых баз и объяснять, почему аналитические хранилища часто строят наоборот — денормализованно.
Зачем нужна нормализация
Представьте таблицу заказов, где в каждой строке дублируются имя клиента, его email и адрес. Клиент меняет email — нужно обновить сотни строк. Забыли одну — данные противоречат друг другу. Это называется аномалиями обновления.
Нормализация решает три проблемы:
- Аномалия обновления — одно изменение требует обновления множества строк.
- Аномалия вставки — нельзя добавить данные, пока нет связанной записи (например, нельзя добавить нового клиента без заказа).
- Аномалия удаления — удаляя заказ, теряем информацию о клиенте.
На собеседованиях нормальные формы спрашивают на уровне понимания: зачем это нужно, как выглядит 1NF/2NF/3NF, и почему в аналитике часто используют денормализацию. Писать SQL для нормализации обычно не просят — достаточно объяснить на примере таблиц.
Первая нормальная форма (1NF)
Правило: каждая ячейка таблицы содержит одно атомарное значение. Никаких списков, массивов или вложенных таблиц.
До нормализации:
| order_id | customer | products |
|---|---|---|
| 1 | Иванов | Ноутбук, Мышь |
| 2 | Петрова | Клавиатура |
| 3 | Иванов | Монитор, Кабель, Мышь |
Столбец products хранит несколько значений через запятую. Нельзя нормально фильтровать, агрегировать, джойнить по отдельным товарам.
После приведения к 1NF:
| order_id | customer | product |
|---|---|---|
| 1 | Иванов | Ноутбук |
| 1 | Иванов | Мышь |
| 2 | Петрова | Клавиатура |
| 3 | Иванов | Монитор |
| 3 | Иванов | Кабель |
| 3 | Иванов | Мышь |
Каждая ячейка — одно значение. Теперь можно считать количество заказов по товару, фильтровать по конкретному продукту и строить индексы по столбцу product.
Вторая нормальная форма (2NF)
Правило: таблица в 1NF + каждый неключевой столбец зависит от всего первичного ключа целиком, а не от его части.
2NF актуальна для таблиц с составным первичным ключом. Если ключ — одно поле, таблица в 1NF автоматически в 2NF.
Проблема — частичная зависимость:
| order_id | product_id | product_name | quantity |
|---|---|---|---|
| 1 | 101 | Ноутбук | 1 |
| 1 | 102 | Мышь | 2 |
| 2 | 101 | Ноутбук | 1 |
Первичный ключ — (order_id, product_id). Столбец product_name зависит только от product_id, а не от всего ключа. Если переименовать товар — нужно обновить все строки.
После приведения к 2NF — разделяем на две таблицы:
Таблица order_items:
| order_id | product_id | quantity |
|---|---|---|
| 1 | 101 | 1 |
| 1 | 102 | 2 |
| 2 | 101 | 1 |
Таблица products:
| product_id | product_name |
|---|---|
| 101 | Ноутбук |
| 102 | Мышь |
Название товара хранится в одном месте. Изменение — одна строка.
Третья нормальная форма (3NF)
Правило: таблица в 2NF + нет транзитивных зависимостей. Неключевой столбец не должен зависеть от другого неключевого столбца.
Проблема — транзитивная зависимость:
| order_id | customer_id | customer_name | customer_city |
|---|---|---|---|
| 1 | 10 | Иванов | Москва |
| 2 | 11 | Петрова | Казань |
| 3 | 10 | Иванов | Москва |
Первичный ключ — order_id. Столбцы customer_name и customer_city зависят от customer_id, а не напрямую от order_id. Это транзитивная зависимость: order_id -> customer_id -> customer_name.
После приведения к 3NF:
Таблица orders:
| order_id | customer_id |
|---|---|
| 1 | 10 |
| 2 | 11 |
| 3 | 10 |
Таблица customers:
| customer_id | customer_name | customer_city |
|---|---|---|
| 10 | Иванов | Москва |
| 11 | Петрова | Казань |
Теперь данные о клиенте хранятся в одном месте. Изменение города — обновление одной строки в customers.
BCNF
Нормальная форма Бойса-Кодда (BCNF) — усиленная версия 3NF. Требование: каждая нетривиальная функциональная зависимость должна исходить от суперключа. На практике разница между 3NF и BCNF проявляется редко — только в таблицах с несколькими перекрывающимися составными ключами.
На собеседованиях аналитиков BCNF спрашивают нечасто. Достаточно знать, что она существует и является «строгой версией 3NF». Если спросили — ответьте одним предложением и переходите к денормализации.
Денормализация для аналитики
Нормализация хороша для транзакционных (OLTP) баз: меньше дублирования, проще обновления. Но аналитические запросы — это совсем другая история. Аналитику нужно:
- Читать миллионы строк, а не обновлять по одной.
- Минимизировать джойны — каждый JOIN замедляет тяжёлый запрос.
- Быстро агрегировать данные по разным срезам.
Поэтому аналитические хранилища (DWH) строят денормализованно:
- Схема «звезда» (Star Schema) — центральная таблица фактов (например,
fact_orders) окружена таблицами измерений (dim_customers,dim_products,dim_dates). Факты хранят числовые метрики и ключи измерений. Один уровень джойнов вместо каскада. - Плоские таблицы (flat tables) — все данные собраны в одну широкую таблицу. Никаких джойнов. Максимальная скорость чтения за счёт дублирования.
- Колоночные БД (ClickHouse, BigQuery, Redshift) — оптимизированы под чтение столбцов, а не строк. Денормализация здесь работает особенно хорошо.
Аналитик должен понимать оба подхода: нормализация — как устроена продуктовая база, денормализация — как устроено хранилище, из которого он строит отчёты.
Вопросы с собеседований
— Что такое нормализация и зачем она нужна? — Нормализация — процесс разделения таблиц для устранения избыточности данных и аномалий обновления, вставки, удаления. Каждый факт хранится в одном месте, что упрощает поддержку и гарантирует целостность данных.
— Объясните разницу между 1NF, 2NF и 3NF. — 1NF: атомарные значения в каждой ячейке, никаких списков. 2NF: нет частичных зависимостей от составного ключа. 3NF: нет транзитивных зависимостей — неключевые столбцы зависят только от первичного ключа, а не от других неключевых столбцов.
— Почему аналитические базы данных часто денормализованы? — Аналитические запросы читают большие объёмы данных и агрегируют по разным срезам. Денормализация сокращает количество джойнов, ускоряет чтение и упрощает запросы. Дублирование данных — осознанный компромисс ради скорости.
— Что такое схема «звезда»? — Модель данных для хранилища: центральная таблица фактов (транзакции, события) окружена таблицами измерений (клиенты, товары, даты). Один уровень джойнов. Оптимизирована для аналитических запросов и инструментов BI.
— Когда нормализация вредна? — Когда приоритет — скорость чтения, а не целостность записи. В OLAP-системах, отчётных витринах и дашбордах нормализация создаёт лишние джойны без пользы. Также нормализация может быть избыточна для маленьких справочников или логов, которые только записываются и читаются.
Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.
FAQ
Нужно ли аналитику уметь нормализовать базу данных?
Проектировать схему с нуля — задача инженера данных или DBA. Но аналитик должен понимать, почему таблицы связаны через ключи, откуда берутся джойны и почему в продуктовой базе данные о клиенте лежат отдельно от заказов. На собеседовании достаточно объяснить 1NF/2NF/3NF на примерах и аргументировать, когда денормализация оправдана.
Какую нормальную форму считают достаточной?
В большинстве продуктовых баз останавливаются на 3NF. Дальнейшая нормализация (BCNF, 4NF, 5NF) даёт минимальный выигрыш при заметном усложнении структуры. На собеседованиях тоже редко заходят дальше третьей формы.
Как нормализация связана с производительностью SQL-запросов?
Нормализованная база требует больше джойнов — это может замедлять тяжёлые аналитические запросы. Но для транзакционных операций (вставка, обновление) нормализация ускоряет работу: меньше данных для записи, меньше блокировок. Правильные индексы помогают компенсировать стоимость джойнов.
Где потренировать SQL-запросы с джойнами по нормализованным таблицам?
В тренажёре Карьерник есть задачи на джойны, агрегации и подзапросы по реалистичным нормализованным схемам. Посмотреть формат вопросов можно в примерах.