Что такое нормальная форма Бойса-Кодда (BCNF) в базах данных?

Ответ

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

Определение: Таблица находится в BCNF, если для каждой нетривиальной функциональной зависимости X → Y детерминант X является суперключом (т.е. содержит потенциальный ключ таблицы).

Проблема, которую решает BCNF: В 3НФ возможна ситуация, когда неключевой атрибут функционально определяет часть составного ключа, что приводит к избыточности и аномалиям обновления.

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

Исходная таблица Enrollment не в BCNF:

-- {student_id, subject} → professor, но также professor → subject
-- professor не является суперключом, нарушение BCNF.
CREATE TABLE Enrollment (
    student_id INT,
    subject VARCHAR(50),
    professor VARCHAR(50),
    PRIMARY KEY (student_id, subject)
);

Нормализация: Разделяем на две таблицы, устраняя зависимость неключевого атрибута.

-- Таблица 1: Профессор определяет предмет (professor — суперключ).
CREATE TABLE ProfessorSubject (
    professor VARCHAR(50) PRIMARY KEY,
    subject VARCHAR(50)
);

-- Таблица 2: Связь студента и профессора.
CREATE TABLE StudentEnrollment (
    student_id INT,
    professor VARCHAR(50),
    PRIMARY KEY (student_id, professor),
    FOREIGN KEY (professor) REFERENCES ProfessorSubject(professor)
);

Результат: Обе новые таблицы находятся в BCNF, аномалии устранены.

Ответ 18+ 🔞

Ну, вот смотри, ты сидишь, думаешь, что с базой всё чики-пуки, 3НФ вроде соблюдена, а потом — бац! — и вылезает какая-то хуйня при обновлении. И ты такой: «Ёпта, как так? Я же нормализовал!». А всё потому, что есть эта самая, блядь, Нормальная форма Бойса-Кодда (BCNF), которая, по сути, берёт 3НФ и дожимает её, как последнего мудака в тренажёрке.

Если по-простому: Таблица в BCNF, если для каждой нетривиальной зависимости X → Y этот самый Xсуперключ. То есть он должен быть таким крутым, что по нему можно однозначно всю строку идентифицировать. Если X — какая-то хилая часть ключа или вообще не ключ, то это нарушение, и тебе пизда, нужно дробить таблицу дальше.

В чём, собственно, прикол? В 3НФ могут проскочить зависимости, где неключевой атрибут определяет часть составного ключа. И вот эта хуйня порождает избыточность: ты меняешь профессора в одной записи, а у тебя в десяти других этот же предмет ведёт другой чувак, и возникает пиздец и рассогласование. BCNF эту брешь затыкает.

Разберём на живом примере, чтобы понятно было:

Допустим, есть таблица записи студентов Enrollment. Студент и предмет — ключ. Но ещё есть профессор, который этот предмет ведёт.

CREATE TABLE Enrollment (
    student_id INT,
    subject VARCHAR(50),
    professor VARCHAR(50),
    PRIMARY KEY (student_id, subject)
);

Логика такая: {student_id, subject} → professor. Вроде норм. НО! Допустим, у нас ещё и professor → subject. То есть один профессор — один предмет. И вот профессор-то суперключом не является! Он же не уникально идентифицирует запись — один профессор может учить много студентов. Нарушение BCNF налицо, ёпта!

Что происходит? Если профессор Иванов ведёт «Матан», и мы захотим поменять предмет у Иванова на «Философию», нам придётся лезть и обновлять все записи со студентами, которые к нему записаны. Ебать-колотить, какая же это залупа!

Как это лечится? Дробим, блядь, как дрова!

  1. Выносим зависимость professor → subject в отдельную таблицу, где профессор будет уже главным по тарелке (суперключом).

    CREATE TABLE ProfessorSubject (
        professor VARCHAR(50) PRIMARY KEY,
        subject VARCHAR(50)
    );
  2. В исходной таблице оставляем только связь студента и профессора. Ключ — (student_id, professor).

    CREATE TABLE StudentEnrollment (
        student_id INT,
        professor VARCHAR(50),
        PRIMARY KEY (student_id, professor),
        FOREIGN KEY (professor) REFERENCES ProfessorSubject(professor)
    );

И что в сухом остатке? Теперь всё по-взрослому. Хочешь сменить предмет у профессора — идёшь в ProfessorSubject и меняешь в одной-единственной строке. Никаких аномалий обновления, никакой избыточности. Обе таблицы теперь в BCNF, и можно спать спокойно. Ну, или почти спокойно, пока не доберёшься до 4НФ, но это уже совсем другая история, блядь.