Что такое нормальные формы в базах данных и зачем они нужны?

Ответ

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

Основные нормальные формы:

  1. Первая нормальная форма (1НФ):

    • Правило: Все атрибуты (значения в ячейках) должны быть атомарными (неделимыми). В таблице не должно быть повторяющихся групп столбцов.
    • Пример: Вместо хранения нескольких телефонов в одной строке, их выносят в отдельную таблицу.
    -- Плохо: телефоны хранятся списком в одной ячейке
    CREATE TABLE Users (id INT, name TEXT, phones TEXT); -- phones = '111-111, 222-222'
    
    -- Хорошо: создана отдельная таблица для телефонов
    CREATE TABLE Users (id INT PRIMARY KEY, name TEXT);
    CREATE TABLE UserPhones (user_id INT, phone TEXT, FOREIGN KEY (user_id) REFERENCES Users(id));
  2. Вторая нормальная форма (2НФ):

    • Правило: Таблица находится в 1НФ, и все неключевые атрибуты полностью зависят от всего составного первичного ключа, а не от его части.
    • Пример: В таблице OrderItems с составным ключом (OrderID, ProductID) атрибут ProductName зависит только от ProductID, а не от всего ключа. Это частичная зависимость.
    -- Плохо: ProductName зависит только от части ключа (ProductID)
    CREATE TABLE OrderItems (OrderID INT, ProductID INT, ProductName TEXT, Quantity INT, PRIMARY KEY (OrderID, ProductID));
    
    -- Хорошо: данные о продуктах вынесены в свою таблицу
    CREATE TABLE Products (ProductID INT PRIMARY KEY, ProductName TEXT);
    CREATE TABLE OrderItems (OrderID INT, ProductID INT, Quantity INT, PRIMARY KEY (OrderID, ProductID));
  3. Третья нормальная форма (3НФ):

    • Правило: Таблица находится в 2НФ, и в ней отсутствуют транзитивные зависимости (когда неключевой атрибут зависит от другого неключевого атрибута).
    • Пример: В таблице Employees атрибут DepartmentName зависит от DepartmentID, который, в свою очередь, зависит от первичного ключа EmployeeID.
    -- Плохо: DepartmentName транзитивно зависит от EmployeeID через DepartmentID
    CREATE TABLE Employees (EmployeeID INT PRIMARY KEY, Name TEXT, DepartmentID INT, DepartmentName TEXT);
    
    -- Хорошо: создана отдельная таблица для департаментов
    CREATE TABLE Departments (DepartmentID INT PRIMARY KEY, DepartmentName TEXT);
    CREATE TABLE Employees (EmployeeID INT PRIMARY KEY, Name TEXT, DepartmentID INT);

Существуют и более высокие формы (BCNF, 4НФ, 5НФ), но на практике чаще всего достаточно приведения к 3НФ для достижения баланса между нормализацией и производительностью.