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

Что такое нормализация базы данных?

1.2 Junior🔥 301 комментариев
#Базы данных и SQL

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

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

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

Что такое нормализация базы данных?

Нормализация БД для Business Analyst

Нормализация — это процесс организации данных в БД так, чтобы минимизировать дублирование и обеспечить консистентность. Хотя это технический вопрос, понимание нормализации помогает мне писать лучшие требования.

Зачем нужна нормализация

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

Табл Users_Orders (BAD):
┌────┬────────┬──────────────────┬──────────┬─────────────────┐
│id  │name    │email             │order_id  │products         │
├────┼────────┼──────────────────┼──────────┼─────────────────┤
│1   │John    │john@example.com  │101       │Phone, Laptop    │
│1   │John    │john@example.com  │102       │Monitor, Mouse   │
│2   │Jane    │jane@example.com  │103       │Keyboard         │
└────┴────────┴──────────────────┴──────────┴─────────────────┘

Проблемы:
- Дублирование данных (John, email повторяется)
- Если email John меняется, нужно обновить 2 строки
- Products как comma-separated list (плохо для search)
- Сложно удалить заказ (потеряю информацию о пользователе?)

Формы нормализации (Normal Forms)

Есть 5 основных форм (1NF - 5NF). Я использую первые 3.

1NF (First Normal Form) — Atomicity

Требование: каждая ячейка содержит только одно значение (не список).

BAD: products = "Phone, Laptop" (список)
GOOD: отдельная таблица Order_Items

Пример нормализации к 1NF:

Before (violates 1NF):
┌────┬────────┬──────────────────────────┐
│id  │name    │products                  │
├────┼────────┼──────────────────────────┤
│1   │John    │Phone, Laptop, Monitor    │
│2   │Jane    │Keyboard                  │
└────┴────────┴──────────────────────────┘

After (1NF):
Users:
┌────┬────────┐
│id  │name    │
├────┼────────┤
│1   │John    │
│2   │Jane    │
└────┴────────┘

User_Products:
┌────┬─────────┐
│uid │product  │
├────┼─────────┤
│1   │Phone    │
│1   │Laptop   │
│1   │Monitor  │
│2   │Keyboard │
└────┴─────────┘

2NF (Second Normal Form) — Non-key dependence

Требование: после выполнения 1NF, все non-key атрибуты зависят от ПСЕ primary key.

Proблема: в таблице Orders есть customer_name
NO: customer_name зависит от customer_id, не от всего primary key
YES: customer_name должна быть в таблице Customers

Пример нормализации к 2NF:

Before (violates 2NF):
Orders:
┌──────┬────────┬──────────┬─────────────┐
│order_id│customer_id│customer_name│amount     │
├──────┼────────┼──────────┼─────────────┤
│101   │1       │John      │$100        │
│102   │1       │John      │$200        │
│103   │2       │Jane      │$150        │
└──────┴────────┴──────────┴─────────────┘

Проблема: customer_name зависит от customer_id, не от order_id

After (2NF):
Customers:
┌────┬──────────┐
│id  │name      │
├────┼──────────┤
│1   │John      │
│2   │Jane      │
└────┴──────────┘

Orders:
┌──────┬────────┬────────┐
│id    │cust_id │amount  │
├──────┼────────┼────────┤
│101   │1       │$100    │
│102   │1       │$200    │
│103   │2       │$150    │
└──────┴────────┴────────┘

3NF (Third Normal Form) — No transitive dependence

Требование: non-key атрибуты не зависят друг от друга.

Проблема: zip_code → city → state (транзитивная зависимость)
NO: city зависит от zip_code, не от customer
YES: city и zip_code должны быть отдельно

Пример:

Before (violates 3NF):
Customers:
┌────┬─────┬──────────┬─────────┬───────┐
│id  │name │zip_code  │city     │state  │
├────┼─────┼──────────┼─────────┼───────┤
│1   │John │10001     │New York │NY     │
│2   │Jane │10002     │New York │NY     │
│3   │Bob  │90210     │LA       │CA     │
└────┴─────┴──────────┴─────────┴───────┘

Проблема: city и state зависят от zip_code, не от id
Если изменится city для zip_code 10001, нужно обновить 2 строки

After (3NF):
Customers:
┌────┬─────┬──────────┐
│id  │name │zip_code  │
├────┼─────┼──────────┤
│1   │John │10001     │
│2   │Jane │10002     │
│3   │Bob  │90210     │
└────┴─────┴──────────┘

Zip_Codes:
┌──────────┬─────────┬───────┐
│zip_code  │city     │state  │
├──────────┼─────────┼───────┤
│10001     │New York │NY     │
│10002     │New York │NY     │
│90210     │LA       │CA     │
└──────────┴─────────┴───────┘

Как нормализация влияет на мою работу

Пример: я создаю требование для системы заказов

US-100: Store customer information

Данные для сохранения:
- Customer ID
- Full name
- Email
- Phone
- Address (street, city, state, zip)
- Orders (list of order IDs)

Технический дизайн (нормализованный, 3NF):

Customers (1 запись per customer)
├─ id
├─ name
├─ email
└─ phone

Customer_Addresses (multiple per customer)
├─ id
├─ customer_id
├─ street
├─ city
├─ state
└─ zip

Orders (multiple per customer)
├─ id
├─ customer_id
├─ date
└─ amount

Преимущества нормализованного дизайна:

Нет дублирования

  • Email John хранится 1 раз
  • Если меняется, обновляю 1 место

Консистентность

  • Невозможно иметь несовпадающие данные
  • Foreign keys обеспечивают referential integrity

Гибкость

  • Customer может иметь 0, 1, или много address
  • Легко добавить новые fields

Efficiency

  • Меньше storage
  • Быстрее поиск (особенно с индексами)

Когда я требую денормализацию

Некоторые случаи требуют денормализации (нарушение нормальных форм) для performance.

Пример: Analytics query

Запрос: "Какие города дают больше всего revenue?"

Нормализованный запрос:
SELECT ca.city, SUM(o.amount)
FROM Customers c
JOIN Customer_Addresses ca ON c.id = ca.customer_id
JOIN Orders o ON c.id = o.customer_id
GROUP BY ca.city

Это slow (много JOINs)

Денормализованный подход:
Создаю таблицу Order_Summary с денормализованными данными:
┌──────┬────────┬────────┬─────────┐
│order_id│customer_id│city    │amount   │
├──────┼────────┼────────┼─────────┤
│101   │1       │New York│$100     │
│102   │1       │New York│$200     │
│103   │2       │LA      │$150     │
└──────┴────────┴────────┴─────────┘

Тогда запрос:
SELECT city, SUM(amount) FROM Order_Summary GROUP BY city

Это fast, потому что не нужны JOINs

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

  • Для analytics queries (read-heavy)
  • Для reporting tables
  • Когда performance критична
  • Когда нужны materialized views

Когда избегаю денормализацию:

  • Для operational data (transactional)
  • Когда часто обновляю данные
  • Когда consistency критична

Мой подход к нормализации в требованиях

Я НЕ пишу в US:

❌ "Таблица Users_Orders с полями id, name, email, order_id, products"

Я пишу:

✅ "Система должна сохранять:
- Информацию о пользователе (имя, email, телефон) в таблице Customers
- Заказы (дата, сумма, статус) в таблице Orders
- Товары в заказе в отдельной таблице Order_Items
- Связь: Customers 1-to-many Orders
- Связь: Orders 1-to-many Order_Items

Дизайн должен быть нормализован до 3NF
Уникальные constraints: email уникален в Customers
Foreign keys: order.customer_id -> customers.id"

Типичные ошибки при нормализации

Я требую слишком много нормализации

  • 5NF для простого приложения
  • Результат: complexity и slow queries

Я требую денормализацию для write-heavy систем

  • "Пусть хранит все в одной таблице для speed"
  • Результат: data inconsistency

Я не думаю о queries

  • Нормализую, но потом 10-table JOIN
  • Результат: slow performance

Я балансирую:

  • 3NF как правило (хороший баланс)
  • Денормализация только для читаемых данных
  • Всегда думаю о queries и performance

Итог: нормализация для BA

Я должен знать:

✅ Что такое нормализация (минимизация дублирования) ✅ Зачем она нужна (consistency, flexibility) ✅ Основные формы (1NF, 2NF, 3NF) ✅ Когда требовать нормализацию (operational systems) ✅ Когда допускать денормализацию (analytics, performance)

Я НЕ должен: ❌ Проектировать схему БД (это tech lead) ❌ Писать SQL запросы (это разработчик)

Но я должен: ✅ Требовать нормализацию в требованиях ✅ Обсуждать data design с tech lead ✅ Проверять, что нет очевидных проблем ✅ Думать о performance implications

Главное правило:

Нормализация — это не святое (не нужно быть фанатиком), это инструмент для создания хороших систем. Иногда денормализация дает лучший результат, но это решение должно быть сознательным и обоснованным.