Нормализация базы данных
Нормализация базы данных — это процесс проектирования реляционной базы данных, направленный на устранение избыточности данных и обеспечение их целостности путём приведения структуры таблиц к ряду последовательных нормальных форм. Основная цель нормализации — минимизация дублирования информации и предотвращение аномалий при вставке, обновлении и удалении записей. Концепция была предложена Эдгаром Коддом в 1970 году в рамках реляционной модели данных и впоследствии развита другими исследователями, в частности Реймондом Бойсом и Рональдом Фаджином.
История и предпосылки
До появления реляционных баз данных данные часто хранились в плоских файлах или иерархических структурах, что приводило к значительной избыточности и сложности поддержки. В 1970 году Эдгар Кодд опубликовал работу «A Relational Model of Data for Large Shared Data Banks», где впервые описал реляционную модель. Нормализация стала логическим следствием этой модели: Кодд определил первую, вторую и третью нормальные формы. Позже, в 1974 году, Реймонд Бойс и Эдгар Кодд совместно разработали нормальную форму Бойса — Кодда (BCNF), которая является более строгой версией третьей нормальной формы. В 1979 году Рональд Фаджин ввёл четвёртую нормальную форму, связанную с многозначными зависимостями, а затем и пятую нормальную форму, связанную с зависимостями соединения.
В СССР и России теория нормализации получила распространение в 1980-х — 1990-х годах с развитием СУБД на основе реляционной модели, таких как dBASE, FoxPro, затем PostgreSQL, MySQL и других.
Основные понятия
Для понимания нормализации необходимо знание нескольких базовых терминов реляционной модели:
- Отношение — таблица, состоящая из строк (кортежей) и столбцов (атрибутов).
- Первичный ключ — атрибут или набор атрибутов, однозначно идентифицирующий каждую строку.
- Внешний ключ — атрибут, ссылающийся на первичный ключ другого отношения, для обеспечения ссылочной целостности.
- Функциональная зависимость — связь между двумя наборами атрибутов, при которой значение одного набора однозначно определяет значение другого (обозначается как X → Y).
- Полная функциональная зависимость — зависимость, при которой Y зависит от всего составного ключа X, но не от его подмножества.
Нормальные формы
Процесс нормализации обычно проходит через последовательное приведение таблиц к нормальным формам. Каждая следующая форма накладывает более строгие требования. Важно отметить, что на практике редко требуется нормализация выше третьей нормальной формы (3NF) или нормальной формы Бойса — Кодда.
Первая нормальная форма (1NF)
Таблица находится в первой нормальной форме, если выполнены следующие условия:
- Все атрибуты содержат атомарные (неделимые) значения. Каждое поле хранит одно значение, а не список или массив.
- Все строки уникальны (существует первичный ключ).
- Порядок строк и столбцов не имеет значения.
Пример нарушения: в одной ячейке столбца «Телефоны» перечислены несколько номеров через запятую. Для приведения к 1NF необходимо создать отдельную строку для каждого номера.
Вторая нормальная форма (2NF)
Таблица находится во второй нормальной форме, если она находится в 1NF и каждый неключевой атрибут (не входящий в первичный ключ) функционально полно зависит от всего первичного ключа. Это условие актуально для таблиц с составными первичными ключами. Если атрибут зависит только от части ключа, такую зависимость называют частичной.
Пример нарушения: таблица «Заказы» с составным ключом (ID_заказа, ID_товара) и атрибутом «Цена товара» — цена зависит только от ID_товара, а не от всей комбинации. Требуется вынести информацию о товаре в отдельную таблицу.
Третья нормальная форма (3NF)
Таблица находится в третьей нормальной форме, если она находится в 2NF и отсутствуют транзитивные зависимости — то есть неключевые атрибуты не зависят от других неключевых атрибутов. Иными словами, каждый неключевой атрибут должен напрямую зависеть от первичного ключа.
Пример нарушения: таблица «Сотрудники» с атрибутами: ID_сотрудника (ключ), Отдел, Адрес_отдела. Адрес_отдела зависит от Отдела, а не напрямую от ID_сотрудника. Следует создать отдельную таблицу «Отделы».
Нормальная форма Бойса — Кодда (BCNF)
Нормальная форма Бойса — Кодда является более строгим вариантом 3NF. Таблица находится в BCNF, если для каждой нетривиальной функциональной зависимости X → Y (где Y не является подмножеством X) набор X является потенциальным ключом (сверхключом) отношения. На практике BCNF часто совпадает с 3NF, но существуют ситуации, когда 3NF выполнена, а BCNF — нет. BCNF устраняет остаточные аномалии, возникающие из-за пересекающихся составных ключей.
Четвёртая нормальная форма (4NF)
Таблица находится в четвёртой нормальной форме, если она находится в BCNF и в ней отсутствуют нетривиальные многозначные зависимости. Многозначная зависимость (X →→ Y) возникает, когда заданный набор значений X определяет набор значений Y, не зависящий от остальных атрибутов. Пример: у одного преподавателя может быть несколько курсов и несколько учебных групп — при перечислении всех комбинаций возникает избыточность.
Пятая нормальная форма (5NF)
Пятая нормальная форма (также называемая проективно-соединительной нормальной формой) требует, чтобы любая нетривиальная зависимость соединения в отношении выводилась из его потенциальных ключей. На практике пятая нормальная форма редко применяется, так как большинство реальных баз данных не содержат сложных зависимостей соединения, и её достижение часто ведёт к чрезмерной декомпозиции.
Доменно-ключевая нормальная форма (DKNF)
Доменно-ключевая нормальная форма — высшая ступень нормализации, при которой все ограничения целостности являются логическим следствием определения доменов и ключей. Практическая реализация DKNF чрезвычайно сложна и в большинстве приложений не используется.
Преимущества и недостатки нормализации
Преимущества
- Уменьшение избыточности данных — каждая единица информации хранится в единственном месте.
- Упрощение поддержки целостности — изменение данных производится в одном месте, что исключает рассинхронизацию.
- Уменьшение вероятности аномалий вставки, обновления и удаления.
- Повышение гибкости запросов за счёт более чистого проектирования.
Недостатки
- Сложность структуры — большое количество таблиц и связей может затруднить понимание схемы.
- Снижение производительности при выполнении запросов с множественными соединениями (JOIN). В высоконагруженных системах часто прибегают к денормализации — намеренному отказу от строгих нормальных форм для ускорения операций чтения.
- Увеличение времени на проектирование и внесение изменений.
Практическая реализация
В современной практике проектирования баз данных часто используется процесс нормализации как итеративный метод. Типичная последовательность действий:
- Определить сущности и атрибуты на основе требований.
- Представить данные в виде ненормализованной таблицы.
- Привести таблицу к 1NF, устранив повторяющиеся группы.
- Привести к 2NF, устранив частичные зависимости.
- Привести к 3NF (или BCNF), устранив транзитивные зависимости.
На практике многие проектировщики сразу моделируют схему, находящуюся в 3NF, не проходя через последовательное преобразование. Инструменты CASE (например, ERwin, PowerDesigner, Draw.io) позволяют автоматизировать процесс.
В веб-приложениях и OLTP-системах (системы операционной обработки транзакций) нормализация до 3NF является стандартом. В аналитических системах (OLAP) и хранилищах данных часто используется снежинка или звёздная схема, которые могут быть денормализованы для ускорения агрегаций.
Пример нормализации
Исходная ненормализованная таблица (список заказов):
| Номер заказа | Клиент | Город | Товары |
|---|---|---|---|
| 101 | Иванов | Москва | «Ручка», «Тетрадь» |
| 102 | Петров | Санкт-Петербург | «Карандаш» |
Шаг 1: 1NF — разворачиваем списки товаров в отдельные строки, добавляем первичный ключ (например, составной из номера заказа и товара).
| Номер заказа | Клиент | Город | Товар |
|---|---|---|---|
| 101 | Иванов | Москва | Ручка |
| 101 | Иванов | Москва | Тетрадь |
| 102 | Петров | Санкт-Петербург | Карандаш |
Шаг 2: 2NF — выявляем частичную зависимость: «Клиент» и «Город» зависят только от номера заказа, а не от товара. Создаём две таблицы:
Таблица «Заказы»:
| Номер заказа | Клиент | Город |
|---|---|---|
| 101 | Иванов | Москва |
| 102 | Петров | Санкт-Петербург |
Таблица «Состав заказа»:
| Номер заказа | Товар |
|---|---|
| 101 | Ручка |
| 101 | Тетрадь |
| 102 | Карандаш |
Шаг 3: 3NF — проверяем транзитивную зависимость: «Город» зависит от «Клиента»? Если у клиента всегда один город, то возникает транзитивная зависимость (номер заказа → клиент → город). Создаём отдельную таблицу «Клиенты»:
Таблица «Клиенты»:
| ID_клиента | Имя | Город |
|---|---|---|
| 1 | Иванов | Москва |
| 2 | Петров | Санкт-Петербург |
Таблица «Заказы»: (содержит ID_клиента вместо имени и города)
| Номер заказа | ID_клиента |
|---|---|
| 101 | 1 |
| 102 | 2 |
Таблица «Состав заказа» остаётся без изменений.
После этого схема соответствует третьей нормальной форме.
Критика и альтернативы
Некоторые специалисты отмечают, что излишняя нормализация может привести к избыточному количеству таблиц и сложным запросам. В высоконагруженных системах для повышения производительности чтения применяют денормализацию — сознательное добавление избыточных полей. Другой альтернативой является использование NoSQL-баз данных (документоориентированных, графовых, столбцовых), где нормализация не является обязательным требованием.
Источники
- Codd, E. F. (1970). «A Relational Model of Data for Large Shared Data Banks». Communications of the ACM.
- Date, C. J. (2003). «An Introduction to Database Systems». Addison-Wesley.
- Когаловский М. Р. (2005). «Энциклопедия технологий баз данных». Финансы и статистика.
- Кузнецов С. Д. (2012). «Базы данных: модели и языки». Бином-Пресс.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →