Оптимизация схемы данных

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

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

Эти сведения можно отобразить одной таблицей, в которой каждому устройству будет соответствовать одна строка. Тогда в этой строке должно быть предусмотрено место для указания всех деталей и для количества каждой детали. Но одно устройство может состоять из десяти деталей, а второе – из десяти тысяч. Поэтому в таблице количество столбцов должно быть предусмотрено по максимуму – то есть 10 000. Но, во-первых, это очень неэкономно, поскольку при такой системе записи подавляющее количество ячеек таблицы будет не заполнено. Во-вторых, составить, например, запрос для поиска всех устройств, включающих определенную деталь, оказывается затруднительным.

Более эффективной оказывается организация базы данных в форме двух таблиц. Первая, главная таблица содержит столбцы «Код устройства» и «Название устройства». Вторая, подчиненная таблица содержит список всех вхождений всех деталей в состав всех устройств. Она содержит столбцы «Код устройства», «Код детали», «Название детали» и «Количество деталей». Соединение таблиц осуществляется с помощью полей «Код устройства» в обеих таблицах. При такой организации в состав устройства с кодом N входят все детали, которым в подчиненной таблице приписан код устройства N.

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

Поскольку значения группы полей первичного ключа однозначно определяют строку, можно утверждать, что каждое поле в таблице функционально зависит от полей первичного ключа. Говорят, что база данных удовлетворяет второй нормальной форме, если невозможна ситуация, когда какое-то поле функционально зависит от части первичного ключа. То же самое по-другому можно выразить так: невозможна ситуация, когда для какой-то части полей первичного ключа в каждой группе записей с одинаковыми значениями этих полей значение проверяемого поля одинаковое. Например, если таблица студентов факультета содержит столбцы номера группы, старосты группы, фамилии, а также другие столбцы, то первичным ключом служит совокупность полей группы и фамилии. С другой стороны, фамилия старосты группы зависит только от номера группы. Таким образом, такая таблица не удовлетворяет условиям второй нормальной группы.

Если БД находится в первой нормальной форме, но не во второй, то ее можно нормализовать так, что она станет удовлетворять второй нормальной форме. Например, в приведенном примере следует ввести две таблицы: таблицу групп и таблицу студентов. Полем первичного ключа в таблице групп будет номер группы, полем первичного ключа в таблице студентов будут поля номера группы и фамилии. Но поле старосты надо перенести из таблицы студентов в таблицу групп, там это поле выглядит логичнее. Таблицы надо соединить по полю номера группы.

Таблицы из пары таблиц вида «Устройство – деталь» из первого примера или «Группа – студент» из второго примера называются главной и подчиненной таблицей. Возможны не только пары, но и тройки таблиц последовательного подчинения, например, для таблиц «Отделения» → «Группы» → «Студенты».

Говорят, что база данных удовлетворяет третьей нормальной форме, если невозможна ситуация, когда какое-то поле функционально зависит от группы других полей. То же самое по-другому можно выразить так: невозможна ситуация, когда для какой-то части полей в каждой группе записей с одинаковыми значениями этих полей значение проверяемого поля одинаковое. Отличие от второй нормальной формы в том, что сейчас не требуется, чтобы группа полей входила в состав первичного ключа. Например, если таблица товаров, проданных за день, содержит столбцы «Покупатель», «Код товара по каталогу», «Название товара», «Цена товара», «Количество», то поля «Название товара» и «Цена товара» определяются по полю «Код товара по каталогу» и повторяются во всех строках с одинаковым кодом товара. Данная таблица не удовлетворяет третьей нормальной форме.

Для того, чтобы нормализовать данную ситуацию, надо использовать две таблицы: таблицу проданных товаров со столбцами «Покупатель», «Код товара по каталогу», «Количество», и таблицу «Каталог товаров» со столбцами «Код товара по каталогу», «Название товара», «Цена товара». Эти таблицы надо связать по полю «Код товара по каталогу». Таблица «Каталог товаров» по отношению к полю «Код товара по каталогу» в таблице проданных товаров служит справочником, который позволяет определить название и цену товара по коду.

Итак, использование ненормализованных или плохо нормализованных таблиц в структуре базы данных приведет к следующим проблемам, с которыми столкнется конечный пользователь базы данных:

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

¨ Ввод пользователем большого количества повторяющейся информации неизбежно приведет к возникновению ошибок.

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

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

Для того, чтобы построить достаточно эффективную структуру данных, достаточно придерживаться нескольких простых правил:

¨ Определите таблицы таким образом, чтобы записи в каждой таблице описывали объекты одного и того же класса, например: товары, заказы, потребители.

¨ Если в вашей таблице появляются поля, содержащие аналогичные данные, но относящиеся к разным элементам некоторого списка - разделите таблицу на две, выделив элементы списка в отдельную таблицу.

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

¨ Широко используйте справочники. Например, если в вашей таблице есть поле «Страна», то стоит ввести вспомогательную таблицу «Страны», которая будет содержать соответствующие записи (Россия, Украина, США и т.п.). Этот прием поможет уменьшить количество ошибок при вводе данных, допускаемых пользователями.

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

Поле первичного ключа может иметь определенный смысл, как, например, номер зачетки. Однако очень часто оно не несет никакой смысловой нагрузки и является просто идентификатором объекта в таблице. Во многих случаях удобно использовать в качестве первичного ключа поле счетчика (Counter field). При этом вся ответственность по поддержанию уникальности счетчика снимается с пользователя и перекладывается на СУБД. Поле счетчика представляет собой целое число и автоматически увеличивается на единицу при добавлении пользователем новой записи в таблицу.