Что такое нормализация БД?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Нормализация баз данных
Нормализация БД — это процесс организации таблиц в реляционной базе данных, целью которого является устранение избыточности данных и обеспечение целостности. Это набор правил, которые минимизируют дублирование и улучшают логическую структуру.
Основная идея
Представьте таблицу студентов с их курсами:
Студент | Курс 1 | Курс 2 | Курс 3
---------|---------------|---------------|---------------
Алиса | Математика | Физика | Химия
Боб | Математика | Программирование | NULL
Чарли | Физика | NULL | NULL
Проблемы:
- Если Боб добавит ещё курс, нужно добавить Курс 4 для других
- Сложно обновлять информацию о курсах
- Много NULL значений
После нормализации:
Таблица Students:
id | name
---|------
1 | Алиса
2 | Боб
3 | Чарли
Таблица Courses:
id | name
---|------------------
1 | Математика
2 | Физика
3 | Химия
4 | Программирование
Таблица Enrollments (связная):
student_id | course_id
-----------|----------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 4
3 | 2
Нормальные формы (Normal Forms)
Нормализация определяется несколькими нормальными формами (NF). Каждая следующая форма требует выполнения предыдущей.
1NF (First Normal Form) — Атомарность
Правило: Все значения в ячейках должны быть атомарными (неделимыми).
Ненормализованный пример:
CREATE TABLE students (
id INT,
name VARCHAR(100),
courses VARCHAR(200) -- "Математика, Физика, Химия" — не атомарно!
);
Нормализованный пример:
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE enrollments (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id)
);
2NF (Second Normal Form) — Зависимость от Primary Key
Правило: Все non-key атрибуты должны зависеть от всего primary key, а не от его части.
Ненормализованный пример:
CREATE TABLE student_courses (
student_id INT,
course_id INT,
course_name VARCHAR(100), -- зависит только от course_id, не от student_id!
PRIMARY KEY (student_id, course_id)
);
Нормализованный пример:
CREATE TABLE courses (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE enrollments (
student_id INT,
course_id INT REFERENCES courses(id),
PRIMARY KEY (student_id, course_id)
);
3NF (Third Normal Form) — Отсутствие транзитивных зависимостей
Правило: Non-key атрибуты не должны зависеть друг от друга. Все зависимости должны быть от primary key.
Ненормализованный пример:
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100), -- зависит от customer_id
customer_city VARCHAR(100) -- зависит от customer_id, не от order_id!
);
Нормализованный пример:
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
city VARCHAR(100)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT REFERENCES customers(id)
);
Практический пример: денормализация
Представьте интернет-магазин:
Денормализованная структура (3 таблицы в одной):
CREATE TABLE sales (
id INT PRIMARY KEY,
product_id INT,
product_name VARCHAR(100), -- дублируется
product_price DECIMAL(10,2), -- дублируется
customer_id INT,
customer_name VARCHAR(100), -- дублируется
customer_email VARCHAR(100), -- дублируется
quantity INT,
total DECIMAL(10,2) -- можно вычислить
);
Проблемы:
- Если изменилось имя товара, нужно обновить все строки
- Дублирование данных (5MB × 1000000 строк = 5GB лишних данных)
- Сложный UPDATE ("UPDATE sales SET product_name = ...")
- Аномалии удаления (удалим последний заказ — потеряем данные о товаре)
Нормализованная структура:
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2)
);
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
CREATE TABLE sales (
id INT PRIMARY KEY,
product_id INT REFERENCES products(id),
customer_id INT REFERENCES customers(id),
quantity INT
);
Преимущества:
- Обновить название товара: одна строка в products
- Меньше памяти (только ключи)
- SELECT с JOINами все равно быстрый
Аномалии данных (что решает нормализация)
1. Insert Anomaly (аномалия вставки):
Нельзя добавить нового товара без заказа
2. Update Anomaly (аномалия обновления):
Если изменился email клиента, нужно обновить все его заказы
3. Delete Anomaly (аномалия удаления):
Если удалить последний заказ клиента, потеряем информацию о клиенте
BCNF (Boyce-Codd Normal Form) — строгая версия 3NF
Правило: Каждый детерминант должен быть candidate key.
Осложнённый пример (редко встречается на практике):
-- Ненормализованный пример
CREATE TABLE professor_courses (
professor_id INT,
course_id INT,
time_slot INT,
PRIMARY KEY (professor_id, course_id)
);
-- Проблема: time_slot может зависеть от course_id, а не от professor_id
-- Нормализованный
CREATE TABLE course_schedules (
course_id INT PRIMARY KEY,
time_slot INT
);
CREATE TABLE professor_courses (
professor_id INT,
course_id INT REFERENCES course_schedules(course_id),
PRIMARY KEY (professor_id, course_id)
);
Денормализация: когда это необходимо
Порой денормализация оправдана для производительности:
-- Вместо 3 JOINов при каждом SELECT
SELECT
s.id,
p.name,
c.name,
s.quantity
FROM sales s
JOIN products p ON s.product_id = p.id
JOIN customers c ON s.customer_id = c.id;
-- Можно хранить денормализованный view или кэш
CREATE MATERIALIZED VIEW sales_denormalized AS
SELECT
s.id,
p.name as product_name,
c.name as customer_name,
s.quantity
FROM sales s
JOIN products p ON s.product_id = p.id
JOIN customers c ON s.customer_id = c.id;
Когда денормализовать:
- Запрос часто вызывается (OLAP, аналитика)
- Много тяжёлых JOINов
- Данные меняются редко
- Кэш обновляется периодически
Инструменты для анализа нормализации
import sqlalchemy as sa
from sqlalchemy import inspect
# Проверить структуру таблицы
inspector = inspect(engine)
columns = inspector.get_columns(students)
for col in columns:
print(f"{col[name]}: {col[type]}")
# Проверить foreign keys
fks = inspector.get_foreign_keys(sales)
for fk in fks:
print(f"FK: {fk[constrained_columns]} → {fk[referred_table]}.{fk[referred_columns]}")
Чеклист нормализации
- Все ячейки содержат атомарные значения (1NF)
- Non-key атрибуты зависят от всего primary key (2NF)
- Non-key атрибуты не зависят друг от друга (3NF)
- Нет транзитивных зависимостей (BCNF)
- Избежаны аномалии вставки, обновления и удаления
- Разумная денормализация для производительности
Заключение
Нормализация — это основа хорошей архитектуры БД. Она уменьшает дублирование, упрощает обновления и гарантирует целостность данных. Однако в аналитических системах (OLAP) часто используют контролируемую денормализацию для скорости.