Перейти к содержанию
Educora
Университет30 мин18 / 22

Проектирование баз данных и нормализация

Строй ER-модель, определяй кардинальность связей, находи функциональные зависимости и шаг за шагом декомпозируй таблицы до 1НФ, 2НФ, 3НФ и НФБК.

Проверь себя
В этом уроке ты узнаешь
  • Описывать сущности, атрибуты и связи в ER-модели и превращать связи 1:1, 1:N и M:N в таблицы
  • Находить функциональные зависимости и потенциальные ключи, объяснять аномалии обновления, вставки и удаления
  • Декомпозировать таблицу без потерь до 2НФ, 3НФ и НФБК и оценивать сохранение зависимостей

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

ER-модель: сущности, связи, кардинальность

Проектирование начинается не с таблиц, а с концептуальной модели. Сущность (entity) — то, о чём мы храним данные: ученик, курс, товар. Атрибут — её свойство: имя, цена. Связь (relationship) соединяет сущности: ученик записывается на курс, покупатель заказывает товар. Эту модель в виде диаграмм «сущность–связь» (ER) предложил Питер Чен в 1976 году.

Определение
Кардинальность

Показывает, сколько экземпляров одной сущности может быть связано с одним экземпляром другой: один к одному (1:1), один ко многим (1:N) или многие ко многим (M:N). Кардинальность определяет, в какой таблице окажется внешний ключ.

СвязьПримерКак строится в таблицах
1:1ученик — ученический билетвнешний ключ с UNIQUE во второй таблице или общий первичный ключ
1:Nпокупатель — заказывнешний ключ на стороне «многие»: orders.customer_id
M:Nученики — курсысвязующая таблица с двумя внешними ключами: enrollments
Реляционная база не может хранить связь M:N напрямую — она всегда разбивается на две связи 1:N.

Функциональные зависимости и ключи

Главное понятие нормализации — функциональная зависимость (ФЗ). Запись X → Y означает «значение X однозначно определяет значение Y»: course_id → teacher — зная курс, мы знаем и учителя. ФЗ — не случайное свойство данных, а бизнес-правило: его узнают у специалистов предметной области, а текущие строки таблицы могут его лишь опровергнуть.

X → Y ⇔ ∀ t₁, t₂ ∈ r : t₁[X] = t₂[X] ⇒ t₁[Y] = t₂[Y]
где:
  • Xдетерминант — множество атрибутов
  • Yмножество зависимых атрибутов
  • rлюбое допустимое состояние таблицы (отношения)
  • t₁, t₂любые две строки таблицы; t[X] — значения строки в столбцах X

Две строки, совпадающие по X, обязаны совпадать и по Y.

Множество атрибутов, определяющее все остальные атрибуты, — суперключ; суперключ, из которого нельзя убрать ни одного атрибута, — потенциальный ключ. Один из потенциальных ключей выбирают первичным. Атрибут, входящий хотя бы в один потенциальный ключ, называют ключевым (prime) — это различие понадобится, чтобы отличать 3НФ от НФБК.

Аномалии: чем опасна избыточность

  • Аномалия обновления — один и тот же факт записан в нескольких строках, и при изменении одной копии остальные остаются старыми.
  • Аномалия вставки — один факт нельзя записать без другого (добавить курс, на который ещё никто не записан).
  • Аномалия удаления — удаление одного факта уничтожает другой (вместе с последним зачислением теряется и учитель курса).
SQL
-- a denormalised copy: the teacher is repeated in every row
CREATE TABLE report_flat AS
SELECT e.student_id, s.first_name, e.course_id, c.title, c.teacher, e.score
FROM enrollments AS e
JOIN students AS s ON s.id = e.student_id
JOIN courses  AS c ON c.id = e.course_id;

-- the name is corrected in one row only
UPDATE report_flat SET teacher = 'R. Safarov'
WHERE course_id = 1 AND student_id = 1;

SELECT course_id, teacher, COUNT(*) AS rows_with_it
FROM report_flat
WHERE course_id = 1
GROUP BY course_id, teacher
ORDER BY teacher;
▸ Ожидаемый результат
course_id | teacher | rows_with_it
1 | R. Safarov | 1
1 | Ramin Səfərov | 3
Аномалия обновления: теперь у одного курса два «учителя». В нормализованной базе имя меняется один раз — только в courses.

Нормальные формы: от 1НФ до НФБК

ФормаПравилоТипичное нарушение
1NFв каждой ячейке одно атомарное значение, нет повторяющихся групп, строки различаются ключомphones = '050…, 055…'
2NF1НФ + каждый неключевой атрибут зависит от всего потенциального ключа, а не от его частиключ (student_id, course_id), но student_id → city
3NF2НФ + ни один неключевой атрибут не зависит от другого неключевого (нет транзитивных зависимостей)course_id → teacher → teacher_phone
BCNFдля каждой нетривиальной X → Y X является суперключомteacher → subject, хотя teacher не ключ
Пример 1: декомпозиция до 2НФ

Дана таблица report(student_id, first_name, city, course_id, title, teacher, score) с ключом (student_id, course_id). ФЗ: student_id → first_name, city; course_id → title, teacher; (student_id, course_id) → score. В какой нормальной форме таблица и как её декомпозировать?

Показать решение
1) Все значения атомарны, ключ есть — 1НФ выполняется.
2) first_name и city зависят лишь от части ключа (student_id) — частичная зависимость, 2НФ нарушена. То же с title и teacher.
3) Для каждого детерминанта — своя таблица: students(student_id, first_name, city), courses(course_id, title, teacher), enrollments(student_id, course_id, score).
4) Проверка: в каждой таблице единственный детерминант — её ключ, результат находится в НФБК и в точности повторяет структуру нашей учебной базы.

Декомпозиция должна быть без потерь: соединение частей через JOIN обязано вернуть исходную таблицу без лишних и недостающих строк. Для разбиения на две части это проверяют по теореме Хита: общие столбцы должны быть ключом одной из частей.

(R₁ ∩ R₂) → R₁ ∨ (R₁ ∩ R₂) → R₂
где:
  • R₁, R₂множества атрибутов двух таблиц, полученных декомпозицией (R₁ ∪ R₂ = R)
  • R₁ ∩ R₂общие атрибуты — столбцы, по которым выполняется JOIN

Если условие выполняется, декомпозиция без потерь: R = R₁ ⋈ R₂.

Пример 2: разница между 3НФ и НФБК

lessons(student, subject, teacher): каждый учитель ведёт только один предмет (teacher → subject), а у ученика по каждому предмету один учитель ((student, subject) → teacher). Находится ли таблица в 3НФ? В НФБК? Как привести её к НФБК и что при этом теряется?

Показать решение
1) Потенциальные ключи: (student, subject) и (student, teacher). Все три атрибута ключевые.
2) teacher → subject: teacher не суперключ, но subject — ключевой атрибут; 3НФ это допускает, а НФБК — нет.
3) Декомпозиция до НФБК: teachers(teacher, subject) и assignments(student, teacher). Общий атрибут teacher — ключ первой таблицы, по теореме Хита декомпозиция без потерь.
4) Цена: зависимость (student, subject) → teacher больше нельзя проверить в пределах одной таблицы; не дать ученику двух учителей по одному предмету должны триггер или код приложения.

Когда денормализация оправдана

Нормализация идеальна для повседневных операций (OLTP): много мелких записей, точность, отсутствие противоречий. Аналитические хранилища (OLAP) в основном читают данные, поэтому их денормализуют намеренно: в «схеме звезды» в центре таблица фактов (продажи), а вокруг — широкие таблицы измерений (товар, покупатель, дата), и отчётам хватает нескольких JOIN. Золотое правило: сначала проектируй в 3НФ, а денормализуй только при измеренной проблеме производительности и всегда вместе с механизмом синхронизации (триггер, представление, ночное обновление).

Задание

Восстанови из нормализованных таблиц «плоский» отчёт по курсу Mechanics: имя ученика, город, название курса, учитель и балл. Отсортируй по баллу по убыванию. (При декомпозиции без потерь JOIN в точности возвращает исходную таблицу.)

Задание · SQL
SELECT s.first_name, s.city, c.title, c.teacher, e.score
FROM enrollments AS e
-- join students and courses
WHERE c.title = 'Mechanics'
ORDER BY e.score DESC;
▸ Ожидаемый результат
first_name | city | title | teacher | score
Fidan | Naxçıvan | Mechanics | Ülviyyə Axundova | 94
Murad | Gəncə | Mechanics | Ülviyyə Axundova | 81
Rəşad | Bakı | Mechanics | Ülviyyə Axundova | 77
Elvin | Sumqayıt | Mechanics | Ülviyyə Axundova | 68
Задание

Проверь, что зависимость teacher → subject выполняется на текущих данных: для каждого учителя выведи число разных предметов (subjects), отсортировав по учителю. Если все значения равны 1, данные зависимость не опровергают.

Задание · SQL
SELECT teacher
       -- number of different subjects
FROM courses
GROUP BY teacher
ORDER BY teacher;
▸ Ожидаемый результат
teacher | subjects
Elnur Qasımov | 1
Nərmin Vəliyeva | 1
Ramin Səfərov | 1
Samir Hacıyev | 1
Sara Mitchell | 1
Ülviyyə Axundova | 1

Главное

  • Проектирование начинается с ER-модели; связь M:N строится через связующую таблицу с двумя внешними ключами.
  • Функциональная зависимость X → Y — бизнес-правило: строки, равные по X, обязаны быть равны и по Y.
  • Избыточность порождает аномалии обновления, вставки и удаления; нормализация хранит каждый факт в одном месте.
  • 2НФ устраняет частичные зависимости, 3НФ — транзитивные; в НФБК каждый детерминант — суперключ.
  • Декомпозиция должна быть без потерь (теорема Хита); 3НФ всегда может сохранить зависимости, НФБК — не всегда.
  • Для OLTP используют 3НФ, а для аналитических хранилищ — намеренно денормализованную «схему звезды».

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Как в реляционной базе строится связь M:N между учениками и курсами?