В этом уроке описываются основы работы с базами данных. Напомним,
что под базой данных понимается некоторая унифицированная совокупность
данных, совместно используемая персоналом/населением группы, предприятия,
региона, страны, мира... Задача базы данных состоит в хранении всех представляющих
интерес данных в одном или нескольких местах, причем таким способом, который
заведомо исключает ненужную избыточность. В хорошо спроектированной базе
данных избыточность данных исключается, и вероятность сохранения противоречивых
данных минимизируется. Таким образом, создание баз данных преследует две
основные цели: понизить избыточность данных и повысить их надежность.
Во вводном уроке (номер 1) мы дали краткое, “на пальцах”, толкование локальных и серверных баз данных и пояснили суть технологии клиент-сервер. На данном уроке мы рассмотрим процесс проектирования баз данных, общий для обеих технологий. И лишь детали его реализации будут различаться в разных архитектурах. Сразу оговоримся, что мы будем рассматривать только реляционные базы данных: во-первых, реляционные базы получили наибольшее распространение в мире; во-вторых, они наиболее “продвинуты” в научном плане; а в-третьих, ядро баз данных Borland Database Engine, на основе которого работают все последние продукты компании Borland, предназначено именно для работы с реляционными базами данных.
Жизненный цикл любого программного продукта, в том числе и системы управления базой данных, состоит (по-крупному) из стадий проектирования, реализации и эксплуатации.
Естественно, наиболее значительным фактором в жизненном цикле приложения, работающего с базой данных, является стадия проектирования. От того, насколько тщательно продумана структура базы, насколько четко определены связи между ее элементами, зависит производительность системы и ее информационная насыщенность, а значит - и время ее жизни.
Легко заметить, что отношение является отражением некоторой сущности реального мира (в данном случае - сущности “деталь”) и с точки зрения обработки данных представляет собой таблицу. Поскольку в локальных базах данных каждая таблица размещается в отдельном файле, то с точки зрения размещения данных для локальных баз данных отношение можно отождествлять с файлом. Кортеж представляет собой строку в таблице, или, что то же самое, запись. Атрибут же является столбцом таблицы, или - полем в записи. Домен же представляется неким обобщенным типом, который может быть источником для типов полей в записи. Таким образом, следующие тройки терминов являются эквивалентными:
Атрибут (или набор атрибутов), который может быть использован для однозначной идентификации конкретного кортежа (строки, записи), называется первичным ключом. Первичный ключ не должен иметь дополнительных атрибутов. Это значит, что если из первичного ключа исключить произвольный атрибут, оставшихся атрибутов будет недостаточно для однозначной идентификации отдельных кортежей. Для ускорения доступа по первичному ключу во всех системах управления базами данных (СУБД) имеется механизм, называемый индексированием. Грубо говоря, индекс представляет собой инвертированный древовидный список, указывающий на истинное местоположение записи для каждого первичного ключа. Естественно, в разных СУБД индексы реализованы по-разному (в локальных СУБД - как правило, в виде отдельных файлов), однако, принципы их организации одинаковы.
Возможно индексирование отношения с использованием атрибутов, отличных от первичного ключа. Данный тип индекса называется вторичным индексом и применяется в целях уменьшения времени доступа при нахождении данных в отношении, а также для сортировки. Таким образом, если само отношение не упорядочено каким-либо образом и в нем могут присутствовать строки, оставшиеся после удаления некоторых кортежей, то индекс (для локальных СУБД - индексный файл), напротив, отсортирован.
Для поддержания ссылочной целостности данных во многих СУБД имеется механизм так называемых внешних ключей. Смысл этого механизма состоит в том, что некоему атрибуту (или группе атрибутов) одного отношения назначается ссылка на первичный ключ другого отношения; тем самым закрепляются связи подчиненности между этими отношениями. При этом отношение, на первичный ключ которого ссылается внешний ключ другого отношения, называется master-отношением, или главным отношением; а отношение, от которого исходит ссылка, называется detail-отношением, или подчиненным отношением. После назначения такой ссылки СУБД имеет возможность автоматически отслеживать вопросы “ненарушения“ связей между отношениями, а именно:
I. Первый шаг состоит в определении информационных потребностей базы данных. Он включает в себя опрос будущих пользователей для того, чтобы понять и задокументировать их требования. Следует выяснить следующие вопросы:
Формирование концептуальной модели базы данных включает в себя:
Перечислив все отношения и их атрибуты, уже на этом этапе можно начать устранять излишние позиции. Каждый атрибут должен появляться только один раз; и Вы должны решить, какое отношение будет являться владельцем какого набора атрибутов.
IV. На четвертом шаге определяются атрибуты, которые уникальным образом идентифицируют каждый объект. Это необходимо для того, чтобы система могла получить любую единичную строку таблицы. Вы должны определить первичный ключ для каждого из отношений. Если нет возможности идентифицировать кортеж с помощью одного атрибута, то первичный ключ нужно сделать составным - из нескольких атрибутов. Хорошим примером может быть первичный ключ в таблице работников, состоящий из фамилии, имени и отчества. Первичный ключ гарантирует, что в таблице не будет содержаться двух одинаковых строк. Во многих СУБД имеется возможность помимо первичного определять еще ряд уникальных ключей. Отличие уникального ключа от первичного состоит в том, что уникальный ключ не является главным идентифицирующим фактором записи и на него не может ссылаться внешний ключ другой таблицы. Его главная задача - гарантировать уникальность значения поля.
V. Пятый шаг предполагает выработку правил, которые будут устанавливать и поддерживать целостность данных. Будучи определенными, такие правила в клиент-серверных СУБД поддерживаются автоматически - сервером баз данных; в локальных же СУБД их поддержание приходится возлагать на пользовательское приложение.
Эти правила включают:
Каждый из различных типов связей должен быть смоделирован в базе данных. Существует несколько типов связей:
Связь “один-ко-многим” в большинстве случаев отражает реальную взаимосвязь сущностей в предметной области. Она реализуется уже описанной парой “внешний ключ-первичный ключ”, т.е. когда определен внешний ключ, ссылающийся на первичный ключ другой таблицы. Именно эта связь описывает широко распространенный механизм классификаторов. Имеется справочная таблица, содержащая названия, имена и т.п. и некие коды, причем, первичным ключом является код. В таблице, собирающей информацию - назовем ее информационной таблицей - определяется внешний ключ, ссылающийся на первичный ключ классификатора. После этого в нее заносится не название из классификатора, а код. Такая система становится устойчивой от изменения названия в классификаторах. Имеются способы быстрой “подмены” в отображаемой таблице кодов на их названия как на уровне сервера БД (для клиент-серверных СУБД), так и на уровне пользовательского приложения. Но об этом - в дальнейших уроках.
Связь “многие-ко-многим” в явном виде в реляционных базах данных не поддерживается. Однако имеется ряд способов косвенной реализации такой связи, которые с успехом возмещают ее отсутствие. Один из наиболее распространенных способов заключается во введении дополнительной таблицы, строки которой состоят из внешних ключей, ссылающихся на первичные ключи двух таблиц. Например, имеются две таблицы: КЛИЕНТ и ГРУППА_ИНТЕРЕСОВ. Один человек может быть включен в различные группы, в то время как группа может объединять различных людей. Для реализации такой связи “многие-ко-многим” вводится дополнительная таблица, назовем ее КЛИЕНТЫ_В_ГРУППЕ, строка которой будет иметь два внешних ключа: один будет ссылаться на первичный ключ в таблице КЛИЕНТ, а другой - на первичный ключ в таблице ГРУППА_ИНТЕРЕСОВ. Таким образом в таблицу КЛИЕНТЫ_В_ГРУППЕ можно записывать любое количество людей и любое количество групп.
Итак, после определения таблиц, полей, индексов и связей между таблицами следует посмотреть на проектируемую базу данных в целом и проанализировать ее, используя правила нормализации, с целью устранения логических ошибок. Важность нормализации состоит в том, что она позволяет разбить большие отношения, как правило, содержащие большую избыточность информации, на более мелкие логические единицы, группирующие только данные, объединенные “по природе”. Таким образом, идея нормализации заключается в следующем. Каждая таблица в реляционной базе данных удовлетворяет условию, в соответствии с которым в позиции на пересечении каждой строки и столбца таблицы всегда находится единственное значение, и никогда не может быть множества таких значений.
После применения правил нормализации логические группы данных располагаются не более чем в одной таблице. Это дает следующие преимущества:
Этот процесс включает:
Когда поле в данной записи содержит более одного значения для каждого вхождения первичного ключа, такие группы данных называются повторяющимися группами. 1НФ не допускает наличия таких многозначных полей. Рассмотрим пример базы данных предприятия, содержащей таблицу
ОТДЕЛ со следующими значениями (атрибут, выделенный курсивом, является первичным ключом):Табл. A: ОТДЕЛ
Номер_отдела | Название | Руководитель | Бюджет | Расположение |
100 | продаж | 000 | 1000000 | Москва |
100 | продаж | 000 | 1000000 | Зеленоград |
600 | разработок | 120 | 1100000 | Тверь |
100 | продаж | 000 | 1000000 | Калуга |
Для приведения этой таблицы
к 1НФ мы должны устранить атрибут (поле) Расположение
из таблицы ОТДЕЛ
и создать новую таблицу РАСПОЛОЖЕНИЕ_ОТДЕЛОВ,
в которой определить первичный ключ, являющийся комбинацией номера отдела
и его расположения (Номер_отдела+Расположение
- см. табл. b). Теперь для каждого
расположения отдела существуют различные строки; тем самым мы устранили
повторяющиеся группы.
Номер_отдела | Расположение |
100 | Москва |
100 | Зеленоград |
600 | Тверь |
100 | Калуга |
Следующий важный шаг в процессе нормализации состоит в удалении всех неключевых атрибутов, которые зависят только от части первичного ключа. Такие атрибуты называются частично зависимыми. Неключевые атрибуты заключают в себе информацию о данной сущности предметной области, но не идентифицируют ее уникальным образом. Например, предположим, что мы хотим распределить работников по проектам, ведущимся на предприятии. Для этого создадим таблицу ПРОЕКТ с составным первичным ключом, включающим номер работника и идентификатор проекта (Номер_работника+ИД_проекта, в табл. c выделены курсивом).
Номер_
работника |
ИД_проекта | Фамилия | Назв_проекта | Описание_
проекта |
Продукт |
28 | БРЖ | Иванов | Биржа | <blob> | программа |
17 | ДОК | Петров | Документы | <blob> | программа |
06 | УПР | Сидоров | Управление | <blob> | адм.меры |
В этой таблице возникает следующая проблема. Атрибуты Назв_проекта, Описание_проекта и Продукт относятся к проекту как сущности и, следовательно, зависят от атрибута ИД_проекта (являющегося частью первичного ключа), но не от атрибута Номер_работника. Следовательно, они являются частично зависимыми от составного первичного ключа. То же самое можно сказать и об атрибуте Фамилия, который зависит от атрибута Номер_работника, но не зависит от атрибута ИД_проекта. Для нормализации этой таблицы (приведения ее в 2НФ) удалим из нее атрибуты Номер_работника и Фамилия и создадим другую таблицу (назовем ее РАБОТНИК_В_ПРОЕКТЕ), которая будет содержать только эти два атрибута, и они же будут составлять ее первичный ключ.
Третий этап процесса приведения таблиц к нормальной форме состоит в удалении всех неключевых атрибутов, которые зависят от других неключевых атрибутов. Каждый неключевой атрибут должен быть логически связан с атрибутом (атрибутами), являющимся первичным ключом. Предположим, например, что мы добавили поля Номер_руководителя и Телефон в таблицу ПРОЕКТ, находящуюся в 2НФ (первичным ключом является поле ИД_проекта). Атрибут Телефон логически связан с атрибутом Номер_руководителя, неключевым полем, но не с атрибутом ИД_проекта, являющимся первичным ключом (табл. d).
ИД_проекта | Номер_
руководителя |
Телефон | Назв_
проекта |
Описание_
проекта |
Продукт |
БРЖ | 02 | 2-21 | Биржа | <blob> | программа |
ДОК | 12 | 2-43 | Документы | <blob> | программа |
УПР | 08 | 2-56 | Управление | <blob> | адм.меры |
Для нормализации этой таблицы (приведения ее в 3НФ) удалим атрибут Телефон, изменим Номер_руководителя на Руководитель и сделаем атрибут Руководитель внешним ключом, ссылающимся на атрибут Номер_работника (первичный ключ) в таблице РАБОТНИКИ. После этого таблицы ПРОЕКТ и РАБОТНИКИ будут выглядеть следующим образом:
Табл. E: ПРОЕКТ
ИД_проекта | Руководитель | Назв_
проекта |
Описание_
проекта |
Продукт |
БРЖ | 02 | Биржа | <blob> | программа |
ДОК | 12 | Документы | <blob> | программа |
УПР | 08 | Управление | <blob> | адм.меры |
Табл. F: РАБОТНИКИ
Номер_
работника |
Фамилия | Имя | Отчество | Номер_
отдела |
Код_
профес |
Телефон | Зарплата | |
04 | Иванов | Иван | Иванович | 100 | инж | 2-69 | 500 | |
08 | Петров | Петр | Петрович | 200 | мндж | 2-56 | 1000 | |
23 | Сидоров | Иван | Петрович | 200 | мндж | 2-45 | 800 |
Теперь, когда мы научились проводить нормализацию таблиц с целью устранения избыточного дублирования данных и группирования информации в логически связанных единицах, необходимо сделать ряд замечаний по вопросам проектирования баз данных. Необходимо четко понимать, что разбиение информации на более мелкие единицы с одной стороны, способствует повышению надежности и непротиворечивости базы данных, а с другой стороны, снижает ее производительность, так как требуются дополнительные затраты процессорного времени (серверного или машины пользователя) на обратное “соединение” таблиц при представлении информации на экране. Иногда для достижения требуемой производительности нужно сделать отход от канонической нормализации, при этом ясно осознавая, что необходимо обеспечить меры по предотвращению противоречивости в данных. Поэтому всякое решение о необходимости того или иного действия по нормализации можно принимать только тщательно проанализировав предметную область и класс поставленной задачи. Может потребоваться несколько итераций для достижения состояния, которое будет желаемым компромиссом между четкостью представления и реальными возможностями техники. Здесь уже начинается искусство...
VII. Седьмой шаг является последним в нашем списке, но не последним по важности в процессе проектирования базы данных. На этом шаге мы должны спланировать вопросы надежности данных и, при необходимости, сохранения секретности информации. Для этого необходимо ответить на следующие вопросы:
На данном занятии мы познакомились с основами теории реляционных баз данных, изучили требования к базам данных, а также основные шаги по проектированию баз данных. Кроме того, рассмотрели очень важный для проектирования баз данных вопрос нормализации таблиц и проблемы, связанные с этим процессом. Теперь мы можем осознанно приступать к созданию приложений, работающих с базами данных.