logo search
Книга по БД(Вальке А

5.12.1. Зачем нужна поддержка объектов в серверах бд?

Выше была рассмотрена классическая, традиционная реляционная модель данных и ее конкретная реализация - язык SQL. Однако не все задачи могут быть одинаково хорошо и изящно решены с помощью реляционных баз данных вообще и языка SQL в частности. Рассмотрим те ограничения и неудобства, которые заложены в реляционных СУБД и как использование объектно-ориентированной технологии может помочь в преодолении возникающих трудностей.

Неравноправие атрибутов

Понятие отношения предполагает, что у каждого реального объекта или у каждой реальной сущности, описываемой записью в отношении, есть некоторое количество атрибутов. С точки зрения реляционной модели все эти атрибуты равноправны, находятся на одном уровне абстрации. Это не означает, конечно, что между атрибутами совсем нет никакой разницы. Например, бывают ключевые и не ключевые атрибуты. Суть в том, что атрибуты не могут быть сгруппированы, они не могут быть собраны в иерархию. Все атрибуты в отношении находятся “на одном уровне”.

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

Рассмотрим пример. Предположим, нам надо реализовать в реляционном отношении (в таблице) список сотрудников предприятия для местного отдела кадров. В такой таблице должны быть следующие атрибуты - фамилия, имя, отчество, табельный номер, отдел, должность, дата приема на работу и т.д:

CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} last_name CHAR(40), {фамилия} first_name CHAR(40), {имя} second_name CHAR(40), {отчество} department INTEGER, {отдел} dolgnost CHAR(20), {должность} emp_from DATE, {работает с…} . . . . . . )

При такой структуре данной таблицы все атрибуты “свалены” в кучу. Более правильно было бы сгруппировать фамилию, имя и отчество в новый составной тип под названием “ФИО”, а отдел и должность - в тип “позиция”:

CREATE ROW TYPE fio_t ( last_name CHAR(40), {фамилия} first_name CHAR(40), {имя} second_name CHAR(40) {отчество} )

CREATE ROW TYPE position_t ( department INTEGER, {отдел} dolgnost CHAR(20) {должность} )

После чего определить таблицу уже с учетом структурированных, упорядоченных атрибутов:

CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} fio fio_t, {ФИО} position position_t, {позиция} emp_from DATE, {работает с…} . . . . . . )

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

Ограниченный набор базовых типов

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

Нельзя сказать, что современные реляционные СУБД такой возможности не предоставляют совсем. Например, такие типы данных в Informix Dynamic Server, как BYTE и TEXT предназначены для хранения больших (до 2 ГБт) двоичных и текстовых объектов соответственно. Сервер обеспечивает только хранение таких объектов, он не может сам обрабатывать данные этих типов. Вся обработка должна проводиться на программе‑клиенте. То есть для того, чтобы, например, просмотреть все имеющиеся в базе данных отпечатки пальцев и отобрать те, которые похожи на заданный образец, программа‑клиент должна последовательно просмотреть все имеющиеся отпечатки. Проведение такого просмотра самим сервером, а, тем более, наличие индекса по отпечаткам, значительно бы ускорило обработку такого запроса.

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

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

Рассмотрим простейший пример. Предположим, нам надо хранить информацию об адресах и делать выборку по улице. В Российских городах для названия улиц может использоваться дополнительная нумерация (1-я Парковая, 9-я Парковая) или прилагательное “Большой” или “Малый” (Малая Бронная). Соответственно, существует несколько способов записи таких названий. Следующие три названия обозначают одну и туже улицу:

М.Бронная Бронная, М. Малая Бронная

Очевидно, что если мы будем использовать для хранения названия улиц обычные строковые типы, то придется следить за тем, чтобы в базе данных названия улиц хранились в едином, унифицированном формате. А при запросе на поиск по названию улицы потребуется преобразовывать введенное пользователем название к этому единому формату. Было бы удобнее, если бы можно было определить новый тип данных “Название улицы”, который бы делал это автоматически и, следовательно, минимизировал возможные ошибки. Для данного типа нужно было бы переопределить операцию сравнения, чтобы при сравнении двух значений учитывалось разное написание улиц. Кроме того, для данного типа потребуется переопределить операции сравнения, чтобы сортировка значений данного типа проводилась с учетом разных написаний:

SELECT streets FROM table1 ORDER by streets

. . . . Бауманская Б.Бронная М.Бронная Буденного . . . .

Можно привести и другие примеры, когда стандартного набора базовых типов недостаточно. Введение в ту или иную СУБД новых предопределенных типов не может решить данную проблему - всегда найдется задачу, которую не предусмотрели.

Сложные типы данных

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

Таблица “Дети”

ID

Фамилия

Имя

Отчество

Родитель

7

Иванов

Игорь

Иванович

106

8

Иванова

Анна

Ивановна

106

14

Петров

Сергей

Петрович

107

. .

. . . .

. . .

. . . .

. . ..

Таблица “Сотрудники”:

ID

Фамилия

Имя

Отчество

. . .

106

Иванов

Иван

Иванович

. . . .

107

Петров

Петр

Петрович

. . . .

108

Сидоров

Сидор

Сидорович

. . . .

. .

. . . .

. . .

. . . .

. . ..

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

Во-первых, требуется предпринять определенные меры по поддержанию целостности базы данных, А именно, при удалении информации о родителе необходимо удалить и информацию о детях, нужно следить за тем, чтобы не было “висящих” ссылок и т.д.

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

Если бы в таблице можно было описать поле типа множество, а каждый элемент множества представлял бы запись об одном ребенке, то все перечисленные выше проблемы решались бы автоматически:

CREATE TABLE persons ( tabel_num INTEGER, {табельный номер} last_name CHAR(40), {фамилия} first_name CHAR(40), {имя} second_name CHAR(40), {отчество} children SET OF ( {дети - множество записей вида} last_name CHAR(40), {фамилия ребенка} first_name CHAR(40), {имя ребенка} second_name CHAR(40), {отчество} was_born DATE {дата рождения} ) . . . . . )

Мы рассмотрели один конкретный пример, и убедились, что структура данных “множество” в некоторых задачах может быть очень полезна. Можно привести примеры, когда было бы полезно, если бы в качестве атрибутов в таблице можно было использовать сложные, составные типы данных со структурами “массив”, “список” и т.д. Реляционные СУБД в своей классической теории не позволяют этого сделать.

Специальные методы хранения и доступа

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

Существующие реляционные СУБД весьма эффективно реализуют способы представлениея, хранения, доступа и поиска традиционных реляционных данных - чисел, текстовых строк, дат и т.д. Для ускорения поиска обычно используются методы индексирования на основе B-деревьев или B+-деревьев. Когда же мы пытаемся выполнить запрос на поиск текстовой строки, содержащей внутри себя некоторую заданную подстроку, например:

SELECT name, address FROM companies WHERE name MATCHES “*Рога*”

или пытаемся выбрать информацию по продажам в феврале в течении нескольких лет:

SELECT price FROM contracts WHERE MONTH(was_signed)=2

то использовать стандартные индексы не получается. Оба указанных выше запроса будут обработаны последовательным сканированием.

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

Иерархия данных

В очень многих случаях, данные в той или иной предметной области, образуют иерархическую структуру. Например, на одном предприятии работают продавцы, инженеры и администрация. С точки зрения отдела кадров, структура информации о каждом из сотрудников идентична и включает в себя фамилию, имя, отчество, должность, дату рождения, дату приема на работу и т.д. Эта структура (набор атрибутов) не зависит от того, на какой должности нааходится тот или иной сотрудник.

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

Если мы попытаемся объединить требования отдела кадров и бухгалтерии в единой базе данных, то в стандартных реляционных СУБД мы будем стоять перед выбором: или иметь единую таблицу со всеми возможными атрибутами, или иметь три разных таблицы с разным набором атрибутов.

Первый подход, когда информация о всех сотрудниках хранится в едином файле, приведет к излишнему расходу памяти (серым цветом показаны неиспользуемые поля в таблице):

Фамилия

Имя

Отчество

Должность

Оклад

Премия (%)

Комиссия (%)

Сумма сделок

Иванов

Иван

Иванович

продавец

1000

0.5

500000

Петров

Петр

Петрович

продавец

1000

0.6

400000

Сидоров

Сидор

Сидорович

инженер

1500

20

Матвеев

Матвей

Матвеевич

инженер

1600

20

Степанов

Степан

Степанович

админист.

1700

Кузьмин

Кузьма

Кузьмич

админист.

1800

Другим недостатком такого подхода является необходимость вынесения способа расчета зарплаты на клиентское приложение (или в хранимую процедуру). Это приводит к усложнению программирования и к повышению вероятности возникновения ошибок.

Другой подход предполагает наличие трех разных таблиц - своя таблица для каждой категории сотрудников:

Таблица “Продавцы”

Фамилия

Имя

Отчество

Должность

Оклад

Комиссия (%)

Сумма сделок

Иванов

Иван

Иванович

продавец

1000

0.5

500000

Петров

Петр

Петрович

продавец

1000

0.6

400000

Таблица “Инженеры”

Фамилия

Имя

Отчество

Должность

Оклад

Премия (%)

Сидоров

Сидор

Сидорович

инженер

1500

20

Матвеев

Матвей

Матвеевич

инженер

1600

20

Таблица “Администраторы”

Фамилия

Имя

Отчество

Должность

Оклад

Степанов

Степан

Степанович

админист.

1700

Кузьмин

Кузьма

Кузьмич

админист.

1800

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