Нормализация таблиц базы данных

advertisement
Проектирование и нормализация базы данных
1. Проблемы проектирования
Проектирование информационных систем, включающих в себя базы данных,
осуществляется на логическом и физическом уровнях. Решение проблем проектирования на
физическом уровне во многом зависит от используемой СУБД, зачастую автоматизировано и
скрыто от пользователя. В ряде случаев пользователю предоставляется возможность
настройки отдельных параметров системы, которая не составляет большой проблемы.
Логическое проектирование заключается в определении числа и структуры таблиц,
формировании запросов к БД, определении типов отчетных документов, разработке
алгоритмов обработки информации, создании форм для ввода и редактирования данных в
базе и решении ряда других задач.
Решение задач логического проектирования БД в основном определяется
спецификой задач предметной области. Наиболее важной здесь является проблема
структуризации
данных.
При
проектировании
стриктур
данных
для
автоматизированных систем можно выделить три основных подхода:
1. Сбор информации об объектах решаемой задачи в рамках одной таблицы (одного
отношения) и последующая декомпозиция ее на несколько взаимосвязанных
таблиц на основе процедуры нормализации отношений.
2. Формулирование знаний о системе (определение типов исходных данных и их
взаимосвязей) и требований к обработке данных, получение с помощью
CASE-системы (системы автоматизации проектирования и разработки баз
данных) готовой схемы БД или даже готовой прикладной информационной
системы.
3. Структурирование информации для использования в информационной системе в
процессе проведения системного анализа на основе совокупности правил и
рекомендаций.
Остановимся подробнее на нормализации отношений.
Нормализация (normalization) — это технология, применяемая при
проектировании таблиц, заключающаяся в назначении атрибутов сущностям. Целью
нормализации является минимизация избыточности информации и в более широком
смысле – устранение аномалий данных, появляющихся вследствие избыточности.
Нормализация не устраняет избыточность данных вообще, вместо этого она дает
возможность контролировать избыточность, что позволяет корректно связывать
таблицы базы данных.
Процесс нормализации состоит из нескольких этапов, на каждом из которых
определяются так называемые нормальные формы. Результатом первых трех этапов
являются соответственно первая нормальная форма, 1НФ (First Normal Form— 1NF),
вторая нормальная форма, 2НФ (2NF) и третья нормальная форма, ЗНФ (3NF). С
точки зрения структуры таблиц 2НФ лучше, чем 1НФ, а ЗНФ лучше, чем 2НФ. В
большинстве проектов БД третья нормальная форма (ЗНФ) завершает процесс
нормализации. Однако иногда приходится иметь дело и с четвертой нормальной
формой (4НФ), а в некоторых специальных приложениях могут потребоваться формы
и более высокого уровня, чем четвертая. Такие приложения обычно связаны со
статистическими исследованиями, которые выходят за пределы контекста
большинства бизнес-операций.
2. Необходимость нормализации
Чтобы продемонстрировать процесс нормализации, рассмотрим простейшее
бизнес-приложение. В данном примере мы будем исследовать, работу с упрощенной
базой данных компании по разработке ПО. У каждого проекта имеются свой
1
уникальный номер, название, штат сотрудников и т.д. У каждого сотрудника есть
идентификационный номер и специальность, например, инженер-программист или
постановщик задач.
Для учёта трудозатрат на разработку ПО компания периодически составляет
отчеты, представляющие собой расходы на заработную плату сотрудников по
каждому из проектов. Для этого учитываются человеко-часы, затраченные каждым
работником на выполнение данного контракта, которые умножаются на стоимость
одного часа работы соответствующего специалиста.
Может покачаться, что самый простой и быстрый способ составить
необходимый отчет состоит в том, чтобы создать таблицу, содержимое которой
соответствовало бы форме самого отчета (таб. 1). Причём, общий итог в табл. 1 —
это производный атрибут, который получается умножением отработанных часов на
стоимость часа работы, и поэтому он не хранится в БД.
К сожалению, структура таблицы 1 не соответствует требованиям к
реляционным базам данных, и поэтому не может считаться удобным средством
манипулирования данными.
o Номер проекта (PROJ_NUM) можно было бы использовать в качестве первичного
ключа (или части первичного ключа) однако в нем имеются пустые места (null).
o Вид элементов таблицы стимулирует противоречивость данных. Например,
значение JOB_CLASS (специализация) в одном случае введена как «Системный
аналитик», в другом «Сист. аналитик».
o В таблице имеется очевидная избыточность данных, что приводит к следующим
аномалиям:
• Аномалии обновления: Изменение JOB_CLASS для сотрудника с номером
(EMP_NUM) 105 требует выполнения этого действия в нескольких строках
таблицы, где встречается EMR_NUM = 105.
• Аномалии включения: Для занесения информации в любую строку необходимо
вводить в проект какого-нибудь сотрудника. Если сотрудник еще не включен в
какой-либо проект, то для того, чтобы занести в таблицу сведения о
сотруднике, придется создавать фиктивный проект.
• Аномалии удаления: Если сотрудник с номером 102 увольняется, то
необходимо будет удалить все строки, тле EMP_NUM = 102. При этом может
быть утеряна и важная информация.
Таблица 1. Периодически составляемый отчёт (таблица).
PROJ_N
UM
PROJ_NAME
Номер Наименование
проекта
проекта
15
18
22
Alpha Edit
Beta Base
Delta CAD
Итого:
EMP_NUM
EMP_NAME
JOB_CLASS
CHG_HOUR
Номер
работника
Ф.И.О. работника
Должность
руб/
час
HOURS
трудозатра Общие
ты в часах расходы
101
Семен Иванов
Программист
200
120
24000
102
Андрей Петров
Программист
200
100
20000
110
Антон Сидоров* Сист. аналитик
300
40
12000
103
Федот Антонов
Прграммист
200
250
50000
102
Андрей Петров
Программист
200
280
56000
111
Петр Семенов*
Проектировщик БД
250
80
20000
104
Сидор Федотов
Программист
200
180
36000
105
Иван Андреев
Программист
200
150
30000
110
Антон Сидоров* Системный
аналитик
300
60
18000
266000
2
Может показаться, что структура таблицы работает правильно, и выполнить
отчет очень просто. Однако могут возникнуть следующие проблемы.
Каждый раз, когда на проект назначается новый сотрудник, некоторые
элементы данных (PROJ_NAME, EMP_NAME, CHG_HOUR) приходится вводить без
всякой на то необходимости. Представьте себе объем ненужного ввода данных, если
потребуется ввести 200—300 элементов таблицы. Ведь достаточно ввести
соответствующий идентификационный номер сотрудника, чтобы можно было
идентифицировать, например, Антона Сидорова, его специализацию и стоимость
часа его работы. Поскольку лишь один сотрудник имеет номер 110, его персональные
данные (имя, специальность и т. д.) не должны набираться всякий раз при
обновлении файла таблицы. К сожалению, структура, представленная в таб. 1, не
предоставляет такой возможности.
Избыточность данных, имеющая место в таблице 1, может привести к не
экономному использованию дискового пространства. К тому же избыточность данных
является причиной аномалий. При вводе новых данных, например, может возникнуть
такая строка:
15 Alfa Edit 111 П.Семёнов
Проектировщик БД 280 0
На первый взгляд эти данные корректны. Но разве, Alfa Edit это тот же проект
что и Alpha Edit? A П.Семёнов — та же личность, что и Петр Семенов? Подобная
путаница вызвана проблемой целостности данных, и произошла она потому, что при
вводе информации не соблюдалось правило, предписывающее, что все копии
избыточных данных должны быть идентичны.
При проектировании БД проблемы целостности данных, которые могут быть
вызваны их избыточностью, обязательно должны приниматься во внимание. В среде
реляционных баз данных такие проблемы можно разрешив достаточно легко.
3. Приведение к первой нормальной форме
В реляционной таблице не должно быть повторяющихся групп. Если же такие
группы существуют, то от них необходимо избавиться с тем, чтобы каждая строка
определяла единственное значение сущности. Процедура заключается в добавлении
соответствующего компонента, по крайней мере, в столбец (или столбцы) первичного
ключа. Это означает, что данные, представленные в таб. 1, должны быть
преобразованы к виду, представленному в таб. 2. Удалив повторяющиеся группы, мы
получаем таблицу, приведенную к первой нормальной форме.
Вид, представленный в таб. 2, это более чем просто косметические изменения.
Теперь даже неопытный наблюдатель обратит внимание, что атрибут PROJ_NUM
нельзя использовать в качестве первичного ключа, поскольку номер проекта не
идентифицирует уникально все остальные атрибуты сущности (строки). Например,
значение PROJ_NUM, равное 15, может определять одного из пяти сотрудников.
Первичный ключ, уникально определяющий любое значение атрибута, должен быть
комбинацией атрибутов PROJ_NUM и EMP_NUM.
Таб.2. Организация данных: первая нормальная форма (1НФ)
PROJ_ PROJ_NAME
NUM
EMP_NU EMP_NAME
M
JOB_CLASS
CHG_H
OUR
HOURS
15
Alpha Edit
101
Семен Иванов
Программист
200
120
15
15
Alpha Edit
Alpha Edit
102
110
Андрей Петров
Антон Сидоров*
Программист
Сист. аналитик
200
300
100
40
18
Betta Prog
103
Федот Антонов
Прграммист
200
250
18
18
Beta Prog
Beta Prog
102
111
Андрей Петров
Петр Семенов*
Программист
Проектировщик БД
200
250
280
80
3
22
22
22
Delta CAD
Delta CAD
Delta CAD
104
105
110
Сидор Федотов
Иван Андреев
Антон Сидоров*
Программист
Программист
Системный
аналитик
200
200
300
180
150
60
Зависимости можно установить с помощью диаграммы зависимостей,
представленной на рис. 1.
PROJ_NUM
PROJ_NAME
EMP_NUM
EMP_NAME
JOB_CLASS
CHG_HOUR
HOURS
Транзитивная
зависимость
Частичная зависимость
Частичные зависимости
Рис.1. Диаграмма зависимостей
На рис. 1 необходимо обратить внимание на следующее:
o атрибуты первичного ключа подчеркнуты;
o линии со стрелками над сущностями указывают все возможные желательные
зависимости, т.е. зависимости, основанные на первичном ключе;
o линии со стрелками в нижней части диаграммы зависимостей указывают на
необязательные зависимости. Имеются два типа таких зависимостей:
• частичная зависимость. Необходимо знать только значение PROJ_NUM для
определения PROJ_NAME, т. е. PROJ_NAME зависит только от части
первичною ключа. А для определения ЕМР_NAME, JQB_CLASS и CHG_HOUR
необходимо знать только EMP_NUM. Зависимость, определяемая только
частью составного первичного ключа, называется частичной зависимостью;
• транзитивная зависимость. На рис. 1 можно заметить, что CHG_HOUR
зависит от JOB_CLASS. Поскольку ни CHG_HOUR, ни JOB_CLASS не
являются первичными атрибутами — т. е. ни один из этих атрибутов не
является, по крайней мере, частью ключа — в этом случае говорят, что имеет
место транзитивная зависимость. (Другими словами, транзитивная
зависимость это зависимость одного непервичного атрибута от другого
непервичного атрибута.) Проблема здесь состоит в том, что такие
зависимости тоже могут стать причиной аномалии данных.
Обратите внимание, что в таблице имеется составной ключ, в который входят
атрибуты PROJ_NUM и EMP_NUM. Любой атрибут, который, по меньшей мере,
является частью ключа, называется первичным атрибутом или ключевым
атрибутом. Следовательно, и PROJ_NUM, и EMP_NUM являются первичными
(ключевыми) атрибутами. Соответственно, непервичный атрибут (или неключевой
атрибут) не является частью ключа.
Говорят, что таблица приведена к первой нормальной форме (1НФ), если в ней:

определены все ключевые атрибуты;

отсутствуют повторяющиеся группы. Иначе говоря, на пересечении каждого
столбца и каждой строки содержится только одно значение (см. свойства
4
реляционных таблиц), а не множество значений;
 все атрибуты зависят от первичного ключа.
Все реляционные таблицы удовлетворяют требованиям, предъявляемым к 1НФ.
Однако в таблице, приведенной к первой нормальной форме, остаются частичные
зависимости — т. е. зависимости, основанные только на части первичного ключа.
4. Приведение ко второй нормальной форме
Проект реляционной базы данных можно легко усовершенствовать, приведя
таблицы БД к виду, называемому второй нормальной формой (2НФ). Процесс
преобразования 1НФ в 2НФ очень прост. Взяв за основу форму 1НФ, представленную
на рис. 1, необходимо проделать следующее:
1. Записать каждый ключевой компонент и отдельной строке, а затем в последней
строке записать исходный (составной) ключ:
PROJ_NUM
EMP_NUM
PROJ_NUM
EMP_NUM
2. Каждый компонент станет ключом в новой таблице. Иначе говоря, исходную
таблицу необходимо разделить на три таблицы. Назовем эти таблицы PROJECT
(проект), EMPLOYEE (сотрудник) и ASSIGN (назначение) соответственно.
3. После каждого нового ключа записать зависимые атрибуты (для определения
зависимости атрибутов используйте рис. 1). Зависимости для компонентов
исходного ключа можно выявить, прослеживая линии со стрелками в нижней
части диаграммы зависимостей, представленной на рис. 1. Другими словами, три
новые таблицы PROJECT, EMPLOYEE и ASSIGN могут быть описаны следующим
образом:
PROJECT (PROJ_NUM, PROJ_NAME)
EMPLOYEE (EMP_NUM, EMP_NAME, JOB_CLASS, CHG_HOUR)
ASSIGN (PROJ_NUM, EMP_NUM, ASSIGN_HOURS)
4. Поскольку количество часов, затраченных на каждый проект каждым сотрудником, зависит в таблице ASSIGN как от атрибута PROJ_NUM, так и от атрибута
EMP_NUM, мы поместим их в таблицу ASSIGN под названием ASSIGN_HOURS.
Результат этой операции представлен на рис. 2. Теперь большинство аномалий,
которые мы ранее обсуждали, устранено. Например, если мы захотим
добавить/изменить/удалить запись в проекте PROJECT, то необходимо лишь
обратиться к таблице PROJECT и добавить/изменить/удалить только одну строку.
Говорят, что таблица приведена ко второй нормальной форме (2НФ), если:

она приведена к первой нормальной форме;

в ней нет частичных зависимостей, т. е. нет атрибутов, зависящих от части
первичного ключа.
(Но, тем не менее, в таблицах 2НФ может иметь место транзитивная зависимость,
т. е. один или более атрибутов могут функционально зависеть от неключевых
атрибутов).
5
PROJ_NUM
PROJ_NAME
Таблица PROJECT
EMP_NUM
EMP_NAME
JOB_CLASS
CHG_HOUR
Таблица EMPLOYEE
Транзитивная
зависимость
PROJ_NUM
EMP_NUM
ASSIGN_HOURS
Таблица ASSIGN
Рис. 2. Результат приведения ко второй нормальной форме (2НФ).
На рис. 2 все еще видна транзитивная зависимость, которая может стать
причиной аномалий. Например, если стоимость часа работы для данной
специализации, которую имеют несколько сотрудников, изменится, то это изменение
необходимо будет проделать для каждого такого сотрудника. Если вы забудете
обновить какие-то записи, связанные с изменением стоимости часа, то разные
сотрудники, имеющие одну и ту же специализацию, получат разную зарплату.
5. Приведение к третьей нормальной форме
Аномалии данных, созданные в базе данных, представленной на рис. 2, можно
легко устранить, разбив фрагменты или фрагмент, на который указывает линия со
стрелкой транзитивной зависимости (в нижней части диаграммы зависимостей) и
поместив их в отдельную таблицу. Однако атрибут JOB_CLASS должен остаться в
исходной таблице (имеющей 2НФ) в качестве внешнего ключа для того чтобы,
установить связь между исходной таблицей и вновь созданной. Иначе говоря, после
завершения преобразования в нашей базе данных должно быть четыре таблицы:
PROJECT (PROJ_NUM, PROJ_NAME)
ASSIGN (PROJ_NUM, EMP_NUM, ASSIGN_HOURS)
EMPLOYEE (EMP_NUM, EMP_NAME, JOB_CLASS)
JOB (JOB_CLASS, CHG_HOUR)
Выполнив это преобразование, мы устранили транзитивную зависимость
оригинальной таблицы EMPLOYEE, и теперь таблица приведена к третьей
нормальной форме (3НФ).
Говорят, что таблица приведена к третьей нормальной форме (3НФ), если:
• она приведена ко второй нормальной форме (2НФ);
• в ней отсутствуют транзитивные зависимости.
После наведения порядка в структурах таблиц и устранении проблем,
вызванных частичной и транзитивной зависимостями, можно подумать о том, как
улучшить
возможности
манипулирования
данными
и
эксплуатационные
характеристики БД. Необходимо выполнить следующие действия:
o Если в таблице EMPLOYEE ввести для атрибута JOB_CLASS значение
6
«проектировщик баз данных» вместо «проектировщик БД», то возникнет
нарушение ссылочной целостности, поскольку в таблице JOB нет записей для
«проектировщик баз данных». Добавив атрибут JOB_CODE, мы создадим такую
зависимость:
JOB_CODE -> JOB_CLASS, CHG_HR
Новый атрибут приводит к транзитивной зависимости (если вы посчитаете, что
JOB_CODE является подходящим первичным ключом), поскольку при этом
получается, что:
JOB_CLASS -> CHG_HR
o
а это и есть транзитивная зависимость, поскольку неключевой атрибут
JOB_CLASS определяет значение другого неключевого атрибута CHG_HR.
Однако наличие атрибута JOB_CODE значительно уменьшает вероятность
нарушения ссылочной целостности.
практику следования условию атомарности атрибутов — т.е. использования
только таких атрибутов, которые невозможно разбить на составляющие, — можно
считать очень полезной. Очевидно, атрибут EMP_NAME таблицы EMPLOYEE не
является атомарным, поскольку его можно разделить на фамилию, имя и
отчество. Разбивая атрибут на более мелкие, мы тем самым увеличиваем
гибкость модели. Например, если мы введем атрибуты ЕМР_LNAME (фамилия),
EMP__FMAME (имя) и EMP_PNAME (отчество), то нам легче будет создать список
телефонов, отсортированный по фамилии, имени и отчеству. Такая задача
практически невыполнима, если все компоненты имени хранятся внутри одного
атрибута.
6. Нормальная форма Бойса—Кодда (БКНФ)
Таблица приведена к нормальной форме Бойса—Кодда (БКНФ), если каждый
детерминант таблицы является потенциальным ключом. Детерминантом
называется любой атрибут, значения которого определяют другие значения внутри
данной строки. Очевидно, если в таблице имеется только один потенциальный ключ,
то формы ЗНФ и БКНФ эквивалентны. Рассуждая иначе, можно сказать, что форма
БКНФ может быть нарушена, только в том случае, если в таблице имеется более
одного потенциального ключа.
Можно считать БКНФ как особый случай ЗНФ. На самом деле, если
использовать описанную выше технологию нормализации, то большинство таблиц
соответствуют требованиям БКНФ, если они соответствуют требованиям ЗНФ.
Однако рассмотрим случай, если неключевой атрибут является детерминантом
ключевого атрибута. Такое обстоятельство не нарушает условий ЗНФ, но не отвечает
правилам БКНФ, поскольку БКНФ требует, чтобы каждый детерминант в таблице был
потенциальным ключом.
Описанную выше ситуацию, (таблица, приведенная к ЗНФ, не соответствует
требованиям БКНФ), проще объяснить с помощью рис. 3, на котором
прослеживаются следующие функциональные зависимости:
A + B -> С, D
С -> В
В структуре таблицы, представленной на рис. 3, нет ни частичных
зависимостей, ни транзитивных зависимостей (условие С -> В указывает на то, что
неключевой атрибут определяет часть первичного ключа — а эта зависимость не
транзитивна!). Очевидно, что структура таблицы, представленная на рис. 3, отвечает
требованиям ЗНФ. А вот условие С -> В нарушает требования БКНФ.
7
A
B
C
D
Рис. 3. Структура таблицы, приведенной к ЗНФ, но не к БКНФ
Чтобы преобразовать структуру, представленную на рис. 3, в таблицу,
отвечающую требованиям как ЗНФ, так и БКНФ, прежде всего, необходимо изменить
первичный ключ на А + С. Это целесообразно сделать, поскольку зависимость С -> В
означает, что С, по сути дела, является подмножеством В. После этого можно
считать, что таблица приведена к 2НФ, поскольку в ней имеется частичная
зависимость С -> В. Затем, с помощью знакомых процедур декомпозиции, приведем
таблицу к виду, представленному на рис. 4.
A
B
C
D
A
C
B
D
3НФ, но не БКНФ
1НФ
Частичная
зависимость
A
C
3НФ и БКНФ
D
C
B
3НФ и БКНФ
Рис. 4. Декомпозиция структуры таблицы для выполнения требований БКНФ.
7. Нормальные формы более высокого уровня
В некоторых случаях возникает необходимость в приведении таблицы к четвертой
нормальной форме (4НФ). При приведении к 4НФ устраняются многозначные
зависимости. Многозначная зависимость в рассмотренном выше примере (таб. 1)
возникает в случае, если сотрудник, помимо участия в нескольких проектах, может
привлекаться к работе в одной или нескольких государственных, благотворительный
и прочих организациях. Однако, если следовать приведенным выше принципам
проектирования, то вы никогда не столкнетесь с только что описанными проблемами.
Четвертая нормальная форма будет представлять лишь чисто академический
8
интерес, особенно если следить за тем. чтобы таблицы соответствовали следующим
двум правилам:
o Все атрибуты должны зависеть от первичного ключа, но не должны зависеть
друг от друга.
o Ни в одной из строк не должно содержаться двух или более многозначных
сведений о данной сущности.
Существуют нормальные формы и более высоких уровней. Однако такие нормальные
формы, как 5НФ и нормальная форма доменного ключа (ДКНФ), вряд ли встретятся в
реальных бизнес-конфигурациях и представляют по большей части теоретический
интерес.
8. Денормализация
Создание нормализованных отношений является важнейшей частью
проектирования БД, но все же это только одна из задач. В хорошем проекте БД
должны учитываться различные требования к обработке информации. По мере того
как таблицы преобразуются в соответствии с требованиями нормализации, их число
растет. Большее число таблиц влечет за собой увеличение количества операций
обмена данными с диском (операции ввода/вывода) и увеличение времени на
обработку логических связей, что приводит к снижению скорости всей системы в
целом. Поэтому противоречие между эффективностью проекта, информационными
потребностями и скоростью обработки информации чаще всего разрешается поиском
компромисса, который, как правило, состоит в некоторой денормализации.
Денормализация приводит к понижению уровня формы (т.е. в процессе
денормализации форма ЗНФ конвертируется в форму 2НФ). Однако надо отдавать
себе отчет, что повышение производительности посредством денормализации
непременно приведет к повышению уровня избыточности данных.
Нормальные формы низких уровней имеют место (а иногда они просто
необходимы) в специализированных БД, называемых информационными
хранилищами (data warehouses). В таких специализированных БД находят отражение
все возрастающие потребности широты охвата и глубины поиска информации, на
которых основаны системы поддержки решений. В информационных хранилищах, как
правило, используются структуры 2НФ в условиях сложной, многоуровневой
информационной среды, питающейся от множества источников.
Это не означает, что таблицы рабочих баз данных, в которых содержатся
частичные или транзитивные зависимости, можно просто оставить в таком виде.
Ненормализованные таблицы в рабочей БД, кроме возможных аномалий данных,
имеют и другие недостатки:
 невысокая эффективность обновления информации, поскольку программы,
которые считывают и обновляют данные, работают с таблицами больших
размеров;
 затруднен процесс индексирования. Просто непрактично формировать все
индексы для множества атрибутов, расположенных в единственной
ненормализованной таблице;
 ненормализованные таблицы затрудняют стратегии создания представлений.
Таким образом, увеличивая путём денормализации скорость обработки данных, мы
снижаем эффективность обновления таблиц (они становятся больше),
индексирование усложняется и появляется угроза избыточности данных, которая
может стать причиной аномалий данных. Вывод — денормализацию следует
применять с осторожностью.
9
Download