Ответ
Нормальные формы (НФ) - это набор правил для проектирования реляционных баз данных, которые минимизируют избыточность данных и аномалии при операциях вставки, обновления и удаления. Вот основные нормальные формы, которые я применяю на практике:
1. Первая нормальная форма (1NF) Требования:
- Все значения в столбцах атомарны (неделимы)
- Нет повторяющихся групп или массивов
- Каждая запись уникальна
Пример нарушения 1NF:
-- Плохо: телефонные номера как строка с разделителями
CREATE TABLE contacts (
id INT PRIMARY KEY,
name VARCHAR(100),
phones VARCHAR(255) -- Может содержать "+7-999-123-45-67, +7-888-987-65-43"
);
Исправление:
-- Хорошо: отдельная таблица для телефонов
CREATE TABLE contacts (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE contact_phones (
id INT PRIMARY KEY,
contact_id INT,
phone VARCHAR(20),
FOREIGN KEY (contact_id) REFERENCES contacts(id)
);
2. Вторая нормальная форма (2NF) Требования:
- Должна быть 1NF
- Все неключевые атрибуты полностью зависят от всего первичного ключа (нет частичных зависимостей)
Пример нарушения 2NF (составной первичный ключ):
-- Заказ товаров: (order_id, product_id) - составной PK
CREATE TABLE order_items (
order_id INT,
product_id INT,
product_name VARCHAR(100), -- Зависит только от product_id, а не от всего PK
quantity INT,
price DECIMAL(10,2),
PRIMARY KEY (order_id, product_id)
);
Исправление:
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
price DECIMAL(10,2),
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- product_name вынесен в отдельную таблицу
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
-- другие атрибуты продукта
);
3. Третья нормальная форма (3NF) Требования:
- Должна быть 2NF
- Нет транзитивных зависимостей (неключевые атрибуты не зависят от других неключевых атрибутов)
Пример нарушения 3NF:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
department_id INT,
department_name VARCHAR(100), -- Зависит от department_id, а не от id сотрудника
manager_name VARCHAR(100)
);
Исправление:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
CREATE TABLE departments (
id INT PRIMARY KEY,
name VARCHAR(100),
manager_name VARCHAR(100)
);
4. Нормальная форма Бойса-Кодда (BCNF) Требования:
- Усиленная 3NF
- Для любой нетривиальной зависимости X → Y, X должен быть суперключом
Пример нарушения BCNF:
-- Курс, преподаватель, аудитория
-- Предположения: один преподаватель ведет курс в одной аудитории
-- В одной аудитории может быть несколько курсов
CREATE TABLE schedule (
course_id INT,
teacher_id INT,
room_id INT,
PRIMARY KEY (course_id, teacher_id)
);
-- Зависимость: course_id → room_id, но course_id не суперключ
Практическое применение: В реальных проектах я обычно довожу базу до 3NF, так как это оптимальный баланс между нормализацией и производительностью. BCNF и более высокие формы применяю точечно, где это критично для целостности данных.
Когда можно отступать от нормальных форм:
- Денормализация для производительности - дублирование данных для ускорения чтения
- Исторические данные - когда нужно сохранить "снимок" состояния на момент времени
- Reporting/OLAP системы - где важна скорость агрегации, а не обновления
Пример денормализации для отчетов:
-- Нормализованная структура
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT,
total_amount DECIMAL(10,2),
created_at TIMESTAMP
);
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
city VARCHAR(50)
);
-- Денормализованная для отчетов
CREATE TABLE order_reports (
order_id INT PRIMARY KEY,
customer_name VARCHAR(100), -- Дублирование из customers
customer_city VARCHAR(50), -- Дублирование из customers
order_amount DECIMAL(10,2),
order_date DATE
);
Нормальные формы - это инструмент, а не догма. Важно понимать, когда их применять, а когда сознательно отступать для решения конкретных задач.