6 нормальных форм БД
Совсем недавно у нас появился новый раздел “Продвинутый php”, который фактически символизирует переход на следующую ступень на нашем пути от новичков до профессионалов В связи с таким качественных переходом, будет несправедливо не затронуть тему имеющую непосредственной отношение к программированию на php – проектированию базы данных.
При написании небольших программ на php, владеть навыками, которые будут описаны в этой статье, не так важно. Но если Вы беретесь за задачи побольше (какая-нибудь CMS или просто большой портал), то они для Вас будут просто необходимыми.
Вкратце опишу тему нормализации баз данных. Сразу, стоит заметить, что термин нормальная таблица можно воспринимать не только в рамках математического аппарата, но и просто так. Потому что нормальные таблицы, действительно являются нормальными (или даже хорошими ), в том смысле, что при работе с ними всякие трудности практически исключены и время разработки Вашего проекта значительно сокращается.
Официальное определение же гласит, что:
“Нормальная форма — требование, предъявляемое к структуре таблиц в теории реляционных баз данных для устранения из базы избыточных функциональных зависимостей между атрибутами (полями таблиц).”
Сразу приведу примеры трудностей, которые могут возникнуть при работе с не нормальной таблицей (если уж Вы на слово не верите 😉 ).
Предположим, что у нас есть таблица – каталог товаров следующего вида:
id, category, product1, product2, product3
Да, это поля этой таблицы. Я, конечно, немного утрирую, но просто в этом случае недостатки настолько большие, что рассматривать их можно без микроскопа.
В этой таблице хранится весь каталог. Каждая строка состоит из имени категории и списка продуктов, которые в нее входят.
Итак, первый недостаток. Вполне логично предположить, что этот каталог рано или поздно придется редактировать. Все операции над каталогом будем рассматривать в контексте работы с таблицей базы данных. В таком случае, допустимы следующие операции: добавление/удаление/редактирование товара и добавление/удаление/редактирование категории.
Я думаю, Вы уже смекнули, какие трудности нас ожидают
Например, для того, чтобы удалить товар, нам нужно просто очистить нужную ячейку нужной строки. Не такая серьезная проблема, для упрямых программистов ;). Вопрос в том, сколько лишних действий придется сделать для этого. А именно, придется перебрать все ячейки всех строк и найти в одной из них нужное название товара и очистить эту ячейку. Для редактирования товара нужно будет выполнить такой же объем операций. Добавление товара это вообще ночной кошмар в этой ситуации. Во-первых, если все ячейки отведенные под товары в категории уже заняты (все три), то в таблицу придется добавлять новый столбец. Но проблема возникает уже перед этим – для определения свободных мест для продукта, нужно будет пройти их все (или проверить занятые, по крайней мере). Короче проблем много, будем считать, что я Вас убедил.
Перехожу к делу. Нормальных форм существует несколько. Несколько стадий совершенства, так сказать. Для каждого вида, помимо его критериев, я буду приводить методы, которые нужно применять для приведения таблиц в эту форму.
Первая нормальная форма (1NF)
Основные критерии:
- Все строки должны быть различными.
- Все элементы внутри ячеек должны быть атомарными (не списками). Другими словами, элемент является атомарным, если его нельзя разделить на части, которые могут использовать в таблице независимо друг от друга.
Пример не 1NF таблицы:
Категория | Товары |
Книги | Война и Мир, Азбука |
Игрушки | Юла |
В этом примере в одной из ячеек содержится список из двух элементов: Война и Мир, Азбука, т.е. он является не атомарным.
Исправить можно так:
Категория | Товары |
Книги | Война и Мир |
Книги | Азбука |
Игрушки | Юла |
Вот, теперь это таблица в первой нормальной форме.
Методы приведения к 1NF:
- Устраните повторяющиеся группы в отдельных таблицах (одинаковые строки).
- Создайте отдельную таблицу для каждого набора связанных данных.
- Идентифицируйте каждый набор связанных данных с помощью первичного ключа (добавить уникальный id для каждой строки)
Вторая нормальная форма (2NF)
Основные критерии:
- Таблица должна находиться в первой нормальной форме.
- Любое её поле, не входящее в состав первичного ключа, функционально полно зависит от первичного ключа.
Сразу скажу, что если Ваша таблица приведена к первой нормальной форме и у нее установлен уникальный id для каждой строки, то она находится и во второй нормальной форме.
Значение второго правила можно понять на примере, когда первичный ключ таблицы состоит из нескольких полей. То есть каждой строке соответствует уникальный набор из нескольких значение полей таблицы.
Например. Эта таблица находится в первой нормальной форме, но не во второй.
Категория | Дата | Скидка | Товар |
Книги | 10.10 | 10% | PHP for dummies |
Ноутбуки | 11.10 | 20% | Acer |
Книги | 10.10 | 10% | Windows XP |
В этой таблице первичный ключ составляют первые два столбца (Категория и Дата).
Скидка функционально полно зависит от них обоих, так как определяется одновременно категорией и датой. А вот с товаром проблемы. Она зависит только от категории и не зависит от даты (в любой день будет лежать там, пока не купят). Поэтому, говорят, что он зависит функционально не полно от всего первичного ключа и функционально полно от его части (Категория). Это нарушает требования второй нормальной формы.
Исправляется это разделением этой таблицы на две другие:
Категория | Дата | Скидка |
Книги | 10.10 | 10% |
Ноутбуки | 11.10 | 20% |
Книги | 10.10 | 10% |
Категория | Товар |
Книги | PHP for dummies |
Ноутбуки | Acer |
Книги | Windows XP |
Вот и все. Теперь эти таблицы находятся во второй нормальной форме.
Методы приведения к 2NF:
- Создайте отдельные таблицы для наборов значений, относящихся к нескольким записям (Выше мы это сделали).
- Свяжите эти таблицы с помощью внешнего ключа (В нашем случае – это поле Категория).
Третья нормальная форма (3NF)
Основные критерии:
- Таблица находится во второй нормальной форме.
- Любой её не ключевой атрибут функционально зависит только от первичного ключа.
Проще говоря, второе правило требует выносить все не ключевые поля, содержимое которых может относиться к нескольким записям таблицы в отдельные таблицы.
Например, есть у нас таблица:
Имя шпиона | Государство |
Джеймс Бонд | Великобритания |
Ким Филби | СССР |
Штирлиц | СССР |
В этой таблице ключом является имя шпиона. А не ключевым полем – государство, на которое он работает. Вполне логично предположить, что в этой таблице государства могут быть одинаковыми для нескольких записей. И для того, чтобы эта таблица находилась в третей нормальной форме, не обходимо ее разделить на две:
ID | Государство |
1 | Великобритания |
2 | СССР |
Имя шпиона | Государство |
Джеймс Бонд | 1 |
Ким Филби | 2 |
Штирлиц | 2 |
Благодаря этому правилу, при удалении какого-то государства, имена шпионов не будут утеряны
Вообще, говоря, на практике, совершенствовать таблицы заканчивают на этом этапе (приведя их в третью нормальную форму).
Методы приведения к 3NF
- Удаление полей не зависящих от ключа
Нормальная форма Бойса-Кодда (BCNF)
Эта форма почти то же самое, что и третья. С одним небольшим дополнительным условием.
Основные критерии:
- Таблица находится в третьей нормальной форме
- В таблице должен быть только один потенциальный первичный ключ
Другими словами, в таблице должен быть только один первичный ключ и не должно быть других потенциальных вариантов (например, набор не ключевых полей это таблицы).
Методы приведения к BCNF
- Вынести в отдельную таблицу потенциальные первичные ключи
Четвертая нормальная форма (4NF)
Начиная с этой формы, буду приводить лишь краткую информацию о форме и ее критериях, так как практического применения это все не найдет. В общеобразовательных целях, так сказать, поделюсь
Ну, тут как и во всех предыдущих формах требования, включают в себя требования всех предыдущих форм + что-то еще. В это форме дополнительное правило должно исключать многозначные зависимости. Другими словами все строки таблицы должны быть независимыми друг от друга. В том смысле, что наличие какой-то строки X, не должно означать, что строка Y тоже где-то есть в этой таблице.
Пятая нормальная форма (5NF)
В некоторых предыдущих формах, для разрешения требований, мы производили декомпозицию таблицы (выделение некоторых полей в отдельную таблицу) на две другие. Так вот, оказывается, что иногда такого рода декомпозицию нельзя без потерь произвести (на две таблицы именно), но зато можно произвести декомпозицию на 3 и более таблицы. Пятая форма как раз призывает, чтобы все возможные декомпозиции были произведены.
В самом начале статьи я показал, какие проблемы могут возникнуть при работе с не нормальными таблицами. В научной терминологии эти проблемы называют аномалиями. И, собственно, вся иерархия нормальных форм, построена таким образом, что каждая последующая ограничивает список возможных аномалий предыдущей формы. Этот процесс сопутствует процессу уменьшения энтропии базы данных, то есть наличия лишней информации. Мы добрались до 5ой нормальной формы, но этот список, в принципе никто не думал прекращать. Вот и в году Фагин (R. Fagin) опубликовал статью, в которой ввел понятие доменно-ключевой нормальной формы (ДКНФ).
Доменно-ключевая нормальная форма (ДКНФ)
В своей статье Фагин показал, отношение в ДКНФ не имеет аномалий модификации. Другими словами, что бы Вы там не меняли – ничего не потеряется, eсли соблюдены все ограничения относительно ключей и доменов.
На самом деле формулировка слишком общая, но суть ее заключается в том, что если выполнять некоторые правила, то при любых действиях с таблицей ее целостность не пострадает и вся необходимая информация сохранится.
Если рассматривать на примере, то правила действуют примерно так: нельзя просто удалить категорию из таблицы категорий, если с этой категорией связаны продукты из таблицы продуктов. Прежде чем удалять категорию необходимо выполнить предварительные действия в таблице продуктов (например, поле отвечающее за id категории этого товара нужно сделать NULL).
На этом список нормальных форм заканчивается. Поэтому, желаю Вам удачи и внимательности при содержании всех Ваших таблиц, хотя бы в третей нормальной форме 😉
Вопрос: в какой проге Вы проектируете БД (https://i-novice.net/images/normal_db.jpg), я юзаю DBDesigner, но он немного по корявому создает картинку…
Организация базы данных очень важный этап разработки, так же очень важно выбрать правильные типы данных, что бы сделать поиск и операции с базой данных максимально быстрыми
2dobs : то что на картинке - это схема из MS Access. Можно еще использовать MS Visio. Там картинки тоже неплохие получаются.
2webdev : согласен. Но это касается скорее больших проектов с большими нагрузками. Для маленьких - это не так существенно 😉
Такой вопрос: разве в примере про 2NF после разделения первая таблица не перестала удовлетворять 1NF в связи с избыточностью строк? В первой и третьей строке идентичные данные…
Нормализация баз данных один из основопологающих критериев
создания БД. Практически в 80 процентов литературы по языкам пр-я
умалчивает об этом. Спасибо , что затронули данную тему.
Ну товарищи вы полные идиоты. Сначала обсуждаете серьёзные вопросы построения и оптимизации баз данных, а потом начали обсуждать какой-то левый майкрософтовский софт для их реализации. Сначала на UNIX перейдите, а потом уже за базы данных беритесь.
Автор продемонстрировал чудеса собственной тупости(или невнимательности, кому как удобней считать), внимательно смотрим
1
Вторая нормальная форма (2NF)
Основные критерии:
* Таблица должна находиться в первой нормальной форме.
2
Первая нормальная форма (1NF)
Основные критерии:
* Все строки должны быть различными.
3
Категория Дата Скидка
Книги 10.10 10%
Ноутбуки 11.10 20%
Книги 10.10 10%
исходя из 1 утверждения ОБЯЗАТЕЛЬНО соблюдение 12го, но на примере 3го видно что пиСуСий сам ни в зуб ногой
, ни в попу табуреткой, соответственно законный вопрос- а какого он пытается других учить? Дальнейшие попытки выродить что умное, для понимающих столь же убожищьны, а для начинающих просто опасны по уровню тупости, лучше посмотреть вики, там лучше объяснен сам механизм. Не даром говорится доверь дураку богу молится и лоб расшибёт и ризницу испоганит
К сожалению, комментарии Anonimous и vlad02 отвратительная характерная черта нашего Интернета. Господа, если вы что-то хотите публично сказать, соблюдайте, пожалуйста, хороший тон и правила приличия.
Пример с 2NF не совсем удачен.
Название товара на деле не зависит от категории.
Отсюда ошибка в разбиении на две таблицы: после разбиения на две таблицы поле “категория” не может являться ключом, поскольку есть повторяющиеся значения в разных строчках.
Пример можно было бы исправить, добавив поле “потребляет электроэнергию”. Это поле зависело бы только от категории и не зависело бы от даты.
Студент 3-го курс
Спасибо.
Очень полезная статья с хорошими, доступными примерами.Спасибо.
Привет. Несогласен немного с определением требований третьей нормальной формы.
“Любой её не ключевой атрибут функционально зависит только от первичного ключа.”
Я бы определил так:
“Нельзя допускать в таблицах образования транзитивных связей между атрибутами кортежей”.
Ваш пример плохо иллистрирует эту проблему. Во-первых практически все современные СУБД автоматом добавляют поле ID (MSSQL вообще не позволит создать таблицу без ID). Таким образом если в ваш пример добавить поле ID перед полями “ИМЯ ШПИОНА” и “Государство”. То возникнут зависимости ID->”ИМЯ ШПИОНА” и “ИМЯ ШПИОНА”->”ГОСУДАРСТВО”. Таким образом появилась транзитивная связь ID->”ГОСУДАРСТВО”, что по правилу следует нормализовать разделением таблиц.
PS. Воспринимайте нормальные формы как правила для минимизации набора данных. 3NF иллюстрирует этот принцип в полной мере.
People, не читайте ни в коем случае эту идиотскую статью! Автор несет бред, мало того, что приводит глупые примеры, не отражающие сути, ошибается в определениях, он еще делает кошмарные выводы!
Ну как строки могут зависеть друг от друга?! (Это к 4NF), упал с дуба, что ли?! Кортеж это праобраз предиката, выдающего истину на прямом произведении доменов. Предикат - это бл.. не функция сцуко!
Короче 4NF - это просто: нельзя допускать A->B&C..&Z (зависимость A от B&C&..&Z, при условии, того, что множества B..Z независимы.
Отличная статья. Пусть кандидат на категорию “Для чайников”, но очень доступно и понятно.
[…] база данных соответствует 3-й нормальной форме (признаться, ХРО накладывает такое требование к базе […]
Автар, не пиши больше про БД плиз
Вы идиоты !!!!
Вы идиоты !!!!нормально нельзя было обьяснить!!!!
Автор, ты не просто не прав, ты допустил грубейшую ошибку.
Проанализируй, пока не наступит просветление свою фразу:
“Благодаря этому правилу, при удалении какого-то государства, имена шпионов не будут утеряны”
Две таблицы связаны между собой, по полю id. Удалив в главной таблице запись с id 1, и оставив его во второй, мы нарушим что? Правильный ответ: целостность БД, т.к. запись во второй таблице не будет относиться ни к какой сущности.
молодцом. немного теории не завредит
Во втором примере явная ошибка (?)
Не может с данной таблицей первичный ключ состоять из полей Категория и Дата, т.к. там у 1 и 3 записи получаются одинаковые значения первичного ключа.
Автору - пиши статьи правильно!
[…] база данных соответствует 3-й нормальной форме (признаться, ХРО накладывает такое требование к базе […]