Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Нормальные формы в реляционных БД
Нормализация — это один из самых важных аспектов проектирования реляционных баз данных. Нормальные формы (Normal Forms, NF) — это набор правил и критериев, которые определяют качество структуры БД и помогают избежать аномалий при вставке, обновлении и удалении данных.
Определение и цель
Нормальная форма — это набор требований к структуре таблиц, которые исключают:
- Дублирование данных
- Аномалии при обновлении
- Потерю информации при удалении
- Избыточное хранение информации
Иерархия нормальных форм
Существует пять основных нормальных форм плюс дополнительные: BCNF (Boyce-Codd Normal Form).
Нулевая норм. форма (UNF — Unnormalized Form)
Данные без какой-либо нормализации:
-- Ненормализованная таблица (с повторяющимися группами)
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
CustomerName VARCHAR(100),
Products VARCHAR(500), -- Список товаров в одной ячейке
Quantities VARCHAR(500) -- Список количеств
);
-- Пример данных:
Insert INTO Orders VALUES
(1, 'John Smith', 'Laptop, Mouse, Keyboard', '1, 2, 3');
-- Товары хранятся в одной ячейке - это источник проблем
Проблемы:
- Сложный парсинг данных
- Аномалии обновления
- Сложные запросы
Первая нормальная форма (1NF)
Правило: Каждое поле должно содержать атомарное значение (не делимое). Не должно быть повторяющихся групп.
-- Нормализация до 1NF
CREATE TABLE Orders (
OrderID INT,
CustomerName VARCHAR(100),
PRIMARY KEY(OrderID)
);
CREATE TABLE OrderItems (
OrderID INT,
ItemIndex INT,
ProductName VARCHAR(100),
Quantity INT,
PRIMARY KEY(OrderID, ItemIndex),
FOREIGN KEY(OrderID) REFERENCES Orders(OrderID)
);
-- Данные теперь разделены:
Insert INTO Orders VALUES (1, 'John Smith');
Insert INTO OrderItems VALUES (1, 1, 'Laptop', 1);
Insert INTO OrderItems VALUES (1, 2, 'Mouse', 2);
Insert INTO OrderItems VALUES (1, 3, 'Keyboard', 3);
Выгода: Легко добавлять/изменять товары.
Вторая нормальная форма (2NF)
Правило: Таблица в 1NF, плюс все неключевые атрибуты полностью зависят от первичного ключа. Нет частичных зависимостей.
-- Ненормализованная таблица
CREATE TABLE StudentCourses (
StudentID INT,
CourseID INT,
StudentName VARCHAR(100), -- Зависит ТОЛЬКО от StudentID
CourseName VARCHAR(100), -- Зависит ТОЛЬКО от CourseID
Grade CHAR(1), -- Зависит от ОБОИХ
PRIMARY KEY(StudentID, CourseID)
);
-- Проблема: StudentName зависит только от StudentID, не от всего ключа
-- Нормализация до 2NF
CREATE TABLE Students (
StudentID INT PRIMARY KEY,
StudentName VARCHAR(100)
);
CREATE TABLE Courses (
CourseID INT PRIMARY KEY,
CourseName VARCHAR(100)
);
CREATE TABLE Enrollment (
StudentID INT,
CourseID INT,
Grade CHAR(1),
PRIMARY KEY(StudentID, CourseID),
FOREIGN KEY(StudentID) REFERENCES Students(StudentID),
FOREIGN KEY(CourseID) REFERENCES Courses(CourseID)
);
-- Grade зависит от обоих полей ключа - это нормально
Выгода: Исключены аномалии обновления (не нужно обновлять StudentName в нескольких местах).
Третья нормальная форма (3NF)
Правило: Таблица в 2NF, плюс все неключевые атрибуты зависят напрямую только от первичного ключа. Нет транзитивных зависимостей.
-- Ненормализованная таблица с транзитивной зависимостью
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
EmployeeName VARCHAR(100),
DepartmentID INT,
DepartmentName VARCHAR(100), -- Зависит от DepartmentID, а не от EmployeeID
ManagerID INT,
ManagerName VARCHAR(100) -- Зависит от ManagerID, а не от EmployeeID
);
-- Проблема: DepartmentName и ManagerName - косвенные зависимости
-- Нормализация до 3NF
CREATE TABLE Departments (
DepartmentID INT PRIMARY KEY,
DepartmentName VARCHAR(100)
);
CREATE TABLE Managers (
ManagerID INT PRIMARY KEY,
ManagerName VARCHAR(100)
);
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
EmployeeName VARCHAR(100),
DepartmentID INT,
ManagerID INT,
FOREIGN KEY(DepartmentID) REFERENCES Departments(DepartmentID),
FOREIGN KEY(ManagerID) REFERENCES Managers(ManagerID)
);
-- Все атрибуты теперь зависят прямо от EmployeeID
Выгода: Устранены аномалии (изменение имени департамента в одном месте).
Нормальная форма Бойса-Кодда (BCNF)
Правило: Более строгая версия 3NF. Каждый детерминант должен быть候選 ключом (candidate key).
-- Пример нарушения BCNF
CREATE TABLE Professors (
ProfessorID INT,
SubjectID INT,
TimeSlot VARCHAR(20),
PRIMARY KEY(ProfessorID, SubjectID)
);
-- Если один профессор может преподавать только один предмет,
-- то TimeSlot зависит только от ProfessorID, а не от ключа в целом
-- BCNF нормализация
CREATE TABLE ProfessorSubjects (
ProfessorID INT,
SubjectID INT,
PRIMARY KEY(ProfessorID, SubjectID),
UNIQUE(ProfessorID, SubjectID)
);
CREATE TABLE ProfessorSchedules (
ProfessorID INT PRIMARY KEY,
TimeSlot VARCHAR(20),
FOREIGN KEY(ProfessorID) REFERENCES ProfessorSubjects(ProfessorID)
);
Четвёртая нормальная форма (4NF)
Правило: BCNF, плюс нет не-функциональных зависимостей (многозначных зависимостей).
-- Нарушение 4NF: многозначные зависимости
CREATE TABLE CourseInstructor (
CourseID INT,
InstructorID INT,
TextbookID INT,
PRIMARY KEY(CourseID, InstructorID, TextbookID)
);
-- Проблема: если курс может иметь МНОГО инструкторов
-- И МНОГО учебников независимо друг от друга,
-- это многозначная зависимость
-- 4NF нормализация
CREATE TABLE CourseInstructors (
CourseID INT,
InstructorID INT,
PRIMARY KEY(CourseID, InstructorID)
);
CREATE TABLE CourseTextbooks (
CourseID INT,
TextbookID INT,
PRIMARY KEY(CourseID, TextbookID)
);
-- Теперь инструкторы и учебники разделены
Пятая нормальная форма (5NF)
Правило: Также называется PJNF (Project-Join Normal Form). Не должно быть циклических зависимостей на уровне проекции и соединения.
-- Очень редкий случай в практической разработке
-- Используется для сложных отношений в аналитических системах
Сравнительная таблица
┌────────┬────────────────────────────────────────────────────────┐
│ NF │ Требования │
├────────┼────────────────────────────────────────────────────────┤
│ UNF │ Повторяющиеся группы разрешены │
│ 1NF │ Только атомарные значения │
│ 2NF │ 1NF + нет частичных зависимостей от ключа │
│ 3NF │ 2NF + нет транзитивных зависимостей │
│ BCNF │ Строже чем 3NF: каждый детерминант = кандидат ключа │
│ 4NF │ BCNF + нет многозначных зависимостей │
│ 5NF │ 4NF + нет циклических зависимостей │
└────────┴────────────────────────────────────────────────────────┘
Денормализация: когда нарушать правила
-- Иногда денормализация необходима для производительности
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
CustomerID INT,
CustomerName VARCHAR(100), -- Денормализация
CustomerEmail VARCHAR(100), -- Денормализация
TotalAmount DECIMAL(10, 2), -- Кэшированное значение
FOREIGN KEY(CustomerID) REFERENCES Customers(CustomerID)
);
-- Копируем CustomerName и Email для быстрого доступа без JOIN
Когда денормализировать:
- Критическая важность производительности
- Часто используемые одинаковые JOIN'ы
- Кэширование вычисленных значений
- Data Warehouse и аналитические БД
Практический подход
- Начни с 3NF — это оптимум для большинства приложений
- Тесты производительности — если медленно, рассмотри денормализацию
- Редко нужны 4NF и 5NF — используются в специальных случаях
- Документируй решения — почему денормализовано
Резюме
Существует пять основных нормальных форм плюс BCNF:
- 1NF — только атомарные значения
- 2NF — нет частичных зависимостей
- 3NF — нет транзитивных зависимостей (используется в 99% случаев)
- BCNF — каждый детерминант = кандидат ключа
- 4NF — нет многозначных зависимостей
- 5NF — нет циклических зависимостей
Для практической разработки 3NF обычно достаточно, более высокие формы используются редко и в специализированных случаях.