Найти в Дзене
Записки о Java

Первая, вторая и третья нормальные формы в реляционной СУБД: подробное руководство с примерами

Целевая аудитория: Java-разработчики, работающие с реляционными базами данных через JDBC, JPA/Hibernate или Spring Data.
Версия Java: 11
Цель статьи: понять, зачем нужны нормальные формы, как они устраняют избыточность и аномалии, и как это влияет на проектирование Java-приложений. Представьте, что вы разрабатываете систему учёта студентов и курсов. Вы создаёте одну таблицу: И начинаете вносить данные: На первый взгляд — всё работает. Но уже здесь кроются проблемы: Эти проблемы называются аномалиями обновления, и их решают с помощью нормализации — приведения структуры БД к так называемым нормальным формам. Сегодня разберём первую (1NF), вторую (2NF) и третью (3NF) нормальные формы — этого достаточно для 95% реальных задач. Нормальная форма — это набор правил, которым должна соответствовать таблица, чтобы минимизировать дублирование данных и избежать аномалий. Нормализация — это процесс декомпозиции одной «плохой» таблицы на несколько «хороших». Каждое значение в ячейке таблицы долж
Оглавление

Целевая аудитория: Java-разработчики, работающие с реляционными базами данных через JDBC, JPA/Hibernate или Spring Data.
Версия Java: 11
Цель статьи: понять, зачем нужны нормальные формы, как они устраняют избыточность и аномалии, и как это влияет на проектирование Java-приложений.

Введение: зачем вообще нужны нормальные формы?

Представьте, что вы разрабатываете систему учёта студентов и курсов. Вы создаёте одну таблицу:

Рисунок: таблица students_courses
Рисунок: таблица students_courses

И начинаете вносить данные:

Рисунок: данные таблицы students_couses
Рисунок: данные таблицы students_couses

На первый взгляд — всё работает. Но уже здесь кроются проблемы:

  • Если Иванов уйдёт, придётся обновлять все строки с курсом 101.
  • Если курс 101 пока никто не посещает — мы не можем его сохранить.
  • При удалении Алисы мы случайно теряем информацию о том, что она училась на курсе 102.

Эти проблемы называются аномалиями обновления, и их решают с помощью нормализации — приведения структуры БД к так называемым нормальным формам.

Сегодня разберём первую (1NF), вторую (2NF) и третью (3NF) нормальные формы — этого достаточно для 95% реальных задач.

Что такое нормальная форма?

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

Нормализация — это процесс декомпозиции одной «плохой» таблицы на несколько «хороших».

Первая нормальная форма (1NF): атомарность значений

Правило 1NF:

Каждое значение в ячейке таблицы должно быть атомарным (неделимым). Нельзя хранить списки, массивы или повторяющиеся группы в одной колонке.

Пример нарушения 1NF

Допустим, вы решили хранить все курсы студента в одной строке:

Рисунок: пример нарушения 1NF
Рисунок: пример нарушения 1NF

Такая структура:

  • Не позволяет эффективно искать студентов по конкретному курсу.
  • Затрудняет обновление одного курса.
  • Нарушает принцип реляционной модели.

Как привести к 1NF?

Разбиваем на отдельные строки:

Рисунок: приводим таблицу к 1NF
Рисунок: приводим таблицу к 1NF

Теперь каждая ячейка содержит одно значение, и таблица находится в первой нормальной форме.

💡 Важно: большинство современных СУБД (PostgreSQL, MySQL и др.) физически не позволяют хранить массивы в обычных колонках без специальных типов (ARRAY, JSON). Но даже если СУБД позволяет — это не значит, что нужно так делать в реляционной модели.

Вторая нормальная форма (2NF): устранение частичных зависимостей

Предварительное условие:

Таблица уже находится в 1NF.

Правило 2NF:

Все неключевые атрибуты должны зависеть от всего составного первичного ключа, а не от его части.

Другими словами: если у вас составной первичный ключ, то ни одна колонка (кроме ключа) не должна зависеть только от части этого ключа.

Пример нарушения 2NF

Вернёмся к нашей исходной таблице:

Рисунок: пример нарушения 2NF
Рисунок: пример нарушения 2NF

Здесь первичный ключ — составной: (student_id, course_id).

Но:

  • student_name зависит только от student_id.
  • course_title и instructor зависят только от course_id.

Это частичные функциональные зависимости → нарушение 2NF.

Как привести к 2NF?

Разбиваем таблицу на три:

Рисунок: таблица во 2NF
Рисунок: таблица во 2NF

Теперь:

  • В students все атрибуты зависят от student_id.
  • В courses — от course_id.
  • В enrollments — только ключи, и они полностью определяют запись.

✅ Таблицы находятся во второй нормальной форме.

Третья нормальная форма (3NF): устранение транзитивных зависимостей

Предварительное условие:

Таблица уже находится в 2NF.

Правило 3NF (упрощённо):

Неключевые атрибуты не должны зависеть от других неключевых атрибутов.
То есть: все неключевые колонки должны зависеть
только от первичного ключа, и ни от чего больше.

Это устраняет транзитивные зависимости: A → B → C, где A — ключ, а C зависит от B, а не напрямую от A.

Пример нарушения 3NF

Представим таблицу сотрудников:

Рисунок: пример нарушения 3NF
Рисунок: пример нарушения 3NF

Данные:

Рисунок: данные
Рисунок: данные

Здесь:

  • emp_id → department ✅ (прямая зависимость от ключа)
  • emp_id → dept_head ❌ — на самом деле dept_head зависит от department, а не от emp_id!

Это транзитивная зависимость:
emp_id → department → dept_head

Проблемы:

  • При смене руководителя IT-отдела нужно обновить все строки с department = 'IT'.
  • Возможна несогласованность: один сотрудник из IT может иметь dept_head = 'Сидоров', другой — 'Иванов'.

Как привести к 3NF?

Выносим отделы в отдельную таблицу:

Рисунок: пример 3 NF
Рисунок: пример 3 NF

Когда можно (и нужно) отступать от 3NF?

Нормализация — не догма. В некоторых случаях применяют контролируемую денормализацию:

  • Высокая нагрузка на чтение: если JOIN слишком дорог, можно добавить вычисляемое поле (например, order_total вместо суммирования строк заказа).
  • Аналитические системы (OLAP): там часто используют «звёздную» или «снежную» схему, где избыточность допустима ради скорости.
  • Кэширование: иногда дублируют данные для избежания обращения к справочникам.

Но! Даже в этих случаях:

  • Денормализация должна быть явной и документированной.
  • Должны быть механизмы поддержания согласованности (триггеры, фоновые задачи, события).

Заключение

Нормальная форма

Главное правило

Что устраняет

1NF

Все значения — атомарные

Повторяющиеся группы, списки

2NF

Нет частичных зависимостей от составного ключа

Дублирование данных по части ключа

3NF

Нет транзитивных зависимостей (неключевые атрибуты зависят только от ключа)

Логическую избыточность

Нормализация — это инвестиция в надёжность и поддерживаемость вашего приложения.
Как Java-разработчик на Java 11, вы должны понимать эти принципы, чтобы:

  • Проектировать чистые Entity-классы.
  • Писать корректные миграции.
  • Избегать скрытых багов, связанных с дублированием данных.

Помните: хорошая база данных — основа хорошего приложения.