Три манифеста баз данных ретроспектива и перспективы
Архитектура ODMG
Предлагаемая ODMG архитектура показана на рис. 2.1. В этой архитектуре определяются способ хранения данных и разные виды пользовательского доступа к этому “хранилищу данных”17. Единое хранилище данных доступно из языка определения данных, языка запросов и ряда языков манипулирования данными.18 На рис. 2.1 ODL означает Object Definition Language (язык определения объектов), OQL – Object Query Language (язык объектных запросов) и OML – Object Manipulation Language (язык манипулирования объектами).
Рис. 2.1. Архитектура ODMG
Центральной в архитектуре является модель данных, представляющая организационную структуру, в которой сохраняются все данные, управляемые ООСУБД. Язык определения объектов, язык запросов и языки манипулирования разработаны таким образом, что все их возможности опираются на модель данных. Архитектура допускает существование разнообразных реализационных структур для хранения моделируемых данных, но важным требованием является то, что все программные библиотеки и все поддерживающие инструментальные средства обеспечиваются в объектно-ориентированных рамках и должны сохраняться в согласовании с данными.
Основными компонентами архитектуры являются следующие.
Допускается поддержка этими продуктами эквивалентных языков определения, включающих все возможности ODL , но адаптированных под особенности конкретной системы. Тем не менее, наличие спецификации языка ODL в стандарте ODMG является важным, поскольку в языке конкретизируются свойства модели данных.
В одной ООСУБД могут поддерживаться несколько OML . В стандарте ODMG -2 были специфицированы правила связывания для языков C ++ и Smalltalk 19. Практически завершена работа над спецификаций правил связывания для языка Java.
GemStone
Как отмечалось выше, ООСУБД GemStone была одной из первых коммерчески доступных ООСУБД. Система была разработана компанией Servio -Logic совместно с OGI . В исходном варианте системы разработчики GemStone опирались на язык Smalltalk . Хотя в первых выпусках системы ее основной язык назывался Opal , сразу было видно, что в действительности этого всего лишь Smalltalk с поддержкой стабильного хранения объектов, и вскоре название языка было заменено на GemStone Smalltalk . Впоследствии в GemStone была обеспечена поддержка языков C и C ++, но во все времена базовым языком оставался Smalltalk , а все остальные интерфейсы строились поверх базового. И серверная, и клиентская части системы могут работать под управлением всех основных ветвей ОС UNIX и всех развитых вариантов Windows . В настоящее время продукт поддерживается, развивается и распространяется компанией GemStone Systems Inc. ().Система основана на трехзвенной архитектуре клиент-сервер, в которой прикладная обработка данных производится на среднем уровне между процессом взаимодействия с пользователем и процессом, поддерживающим хранилище данных. Важность этого подхода состоит в том, что, если в приложении используется много данных, то код приложения целесообразно расположить на стороне хранилища данных, а если в приложении производится много изменений над небольшим объемом данных, то имеет смысл разместить код приложения на стороне пользователя. Тем самым, архитектура позволяет уменьшить объем сетевого трафика без перегрузки сервера, что повышает скорость обработки данных.
Для управления мультидоступом используется механизм транзакций. Механизм основан на так называемом оптимистическом подходе, при котором каждая сессия работает с собственной локальной копией хранилища объектов, и слияние произведенных в сессиях изменений хранилища происходит при завершении транзакции. Если при завершении транзакции обнаруживается, что произведенные в ней изменения конфликтуют с изменениями других ранее зафиксированных транзакций, то фиксация транзакции не производится, транзакция не завершается, и решение проблемы возлагается на пользователя.
Автоматическая блокировка объектов не производится, но пользователь может явно запросить блокировку, что повышает шансы на успешную фиксацию транзакции.
Для обеспечения безопасности данных поддерживается механизм авторизации доступа на уровне владельца объекта и его группы пользователей, так что может быть ограничен доступ к некоторым объектам или некоторым методам объектов. К каждому объекту приписывается авторизационный объект, содержащий данные о том, какие пользователи и в каком режиме (чтения или изменения) имеют доступ к объекту.
Для восстановления базы данных после сбоев аппаратуры используются механизмы репликации, резервного копирования и журнализации. Любой авторизованный пользователь может запросить выполнения полного или частичного копирования. Восстановление базы данных после сбоя системы или дисковых устройств начинается с использования последней по времени резервной копии. После этого при помощи данных, сохраненных в журнальных файлах, хранилище объектов приводится к состоянию, соответствующему последней до момента сбоя зафиксированной транзакции. Авторизованные пользователи могут также запросить поддержку реплицирования областей хранилища данных.
В системе поддерживается целостность по ссылкам между всеми объектами, поскольку все ссылки основываются на использовании объектных идентификаторов, и объекты, для которых существуют ссылки от других объектов, не могут быть удалены. Для повышения скорости доступа к часто используемым коллекциям обеспечивается средство построения индексов.
Объекты делаются стабильными (т.е. сохраняются в базе данных) путем использования своего рода стабильного корня, называемого коннектором. Все объекты, прямо или косвенно достижимые по объектным ссылкам от коннектора, являются стабильными. В GemStone каждого класса, в котором существует хотя бы один стабильный объект, поддерживается эквивалентная серверная версия класса. Другими словами, один вариант класса служит классом в контексте программирования, а другой – в контексте базы данных.
Такие пары поддерживаются автоматически: если создается класс в смысле Smalltalk , и некоторый объект этого класса становится стабильным, то автоматически создается серверный класс этого объекта (класс в смысле GemStone ). Создание коннектора приводит к появлению экземпляра класса GemStone , эквивалентного классу объекта, который должен быть сделан стабильным. Аналогично, любой объект, достижимый от коннектора, автоматически становится стабильным.
В GemStone поддерживается динамическая сборка мусора (garbage collection ). Процесс-“мусорщик” автоматически освобождает память, занимаемую объектами, на которые отсутствуют ссылки.
В среде GemStone можно использовать различные реализации Smaltalk , а также языки C и C ++. Классы и объекты можно создавать с использованием любого из этих языков, и объекты, созданные на одном языке можно использовать в приложениях, написанных на любом другом языке. Реализация языка C представляет собой набор функций и набор компонентов, преобразующих объекты GemStone в указатели и литералы C и наоборот. Реализация C ++ включает препроцессор в чистый С и библиотеку классов.
Подключения к реляционным системам (например, Oracle или IBM DB 2) производятся через шлюзы. Для синхронизации состояния локальной (управляемой GemStone ) и внешних копий данных обеспечивается автоматическая модификация данных. В зависимости среды и требований к уровню синхронизованности эти обновления выполняются немедленно или же в пакетном режиме.
GemStone можно также использовать для управления данными, соответствующими стандартам OLE и CORBA . Для работы с данными в реляционном стиле поддерживаются стандарты SQL и ODBC .
Идентифицируемость объектов
Для баз данных концепция идентифицируемости объектов (object identity ) сравнительно нова 3. Идея состоит в том, что в модели с идентифицируемостью объектов объект существует независимо от его значения. Таким образом, имеется два понятия эквивалентности объектов: два объекта могут быть идентичны (они представляют собой один и тот же объект) или они могут быть равны (они имеют одно и тоже значение). Это влечет две следствия: первое – разделяемые объекты, а второе – изменения объектов.В модели с идентифицируемыми объектами два объекта могут иметь совместно используемый компонент. Таким образом, схематическим представлением сложного объекта является (ориентированный) граф, в то время как в системе без идентифицируемости объектов таким представлением является (ориентированное) дерево.
Идентифицируемость объектов обеспечивает мощный примитив манипулирования данными, который может служить основой для манипулирования множествами, кортежами или рекурсивными сложными объектами. Поддержка идентифицируемости объектов обеспечивает возможность реализации таких операций, как присваивание объекта, копирование объекта (как глубокое, так и поверхностное) и проверка идентичности объектов и их равенства (как глубокого, так и поверхностного).
Конечно, можно моделировать идентифицируемость объектов в системе, основанной на идентификации посредством значений, путем введения явных идентификаторов объектов. Однако такой подход перекладывает на пользователя бремя обеспечения уникальности идентификаторов объектов и поддержки ссылочной целостности (и это бремя может быть весьма значительным для таких операций, как “сборка мусора”).
Модели с идентифицируемостью объектов являются нормой в императивных языках программирования, где каждый объект, с которым имеет дело программа, идентифицируем и может быть изменен. Идентифицируемость объекта обеспечивается за счет наличия имени переменной или соответствующего физического адреса памяти. Однако эта концепция совершенно нова для чисто реляционных систем, где идентифицируемость кортежей отношения основывается на значениях.
Иерархии классов или типов
Наследование обладает двумя положительными достоинствами. Во-первых, оно является мощным средством моделирования, поскольку обеспечивает возможность краткого и точного описания мира. Во-вторых, эта возможность помогает факторизовать совместно используемые в приложениях спецификации и реализации. 6Наследование способствует повторному использованию кода, потому что каждая программа находится на том уровне, на котором ее может совместно использовать наибольшее число объектов.
Имеется по крайней мере четыре типа наследования: наследование через подстановку, наследование путем включения, наследование через ограничение и наследование через специализацию.
Наследование через подстановку подразумевает, что тип T наследует от типа T ’ , если над объектами типа T можно выполнить больше операций, чем над объектами типа T ’ . Таким образом, вместо объекта типаT ’ всегда можно подставить объект типа T . Этот тип наследования базируется на поведении, а не на значениях.
Наследование путем включения соответствует понятию классификации. В этом случае утверждается, что тип T является подтипом T ’ , если каждый объект типа T является также объектом типа T ’ . Этот тип наследования базируется на структуре, а не на операциях. Примером является тип “квадрат” с методами “получить”, “установить размер” и “раскрашенный квадрат” с методами “получить”, “установить размер” и “раскрасить”.
Наследование через ограничение является частным случаем наследования путем включения. Тип T является подтипом типа T ’ , если к нему относятся все объекты типа T ’ , которые удовлетворяют данному ограничению. Примером такого наследования является класс “подросток” как подкласс класса “человек”: объекты класса “подросток” не имеют дополнительных полей или операций по сравнению с объектами класса “человек”, но они удовлетворяют более специфичным ограничениям (возраст подростков ограничен снизу 13, а сверху 19 годами). 7
При наследовании через специализацию тип T является подтипом T ’ , если объекты типа T являются объектами типа T ’ , но при этом содержат более конкретные данные. Примером являются типы “люди” и “служащие”, где данные о служащих включают все данные о соответствующих людях, но включают некоторые дополнительные поля.
Существующие системы и прототипы в той или иной мере поддерживают эти четыре типа наследования. Авторы Первого манифеста не хотели навязывать какой-либо конкретный стиль наследования. По всей видимости, только потому, что среди самих них не было общего мнения относительно достоинств и недостатков каждого из подходов. Вообще, Первому манифесту свойственно сглаживание разногласий.
Инкапсуляция
Идея инкапсуляции происходит (а) из потребности отчетливо различать спецификации и реализации операций и (б) из потребности в модульности. Модульность необходима для структурирования сложных приложений, разрабатываемых и реализуемых группой программистов. Она также необходима как средство защиты и авторизации.Имеются две точки зрения на проблему инкапсуляции: точка зрения с позиций языка программирования (это исходная точка зрения, поскольку отсюда ведет свое начало сама концепция) и адаптация этой точки зрения применительно к базам данных.
Идея инкапсуляции в языках программирования происходит от абстрактных типов данных. С этой точки зрения объект делится на интерфейсную и реализационную части. Интерфейсная часть является спецификацией набора допустимых над объектом операций. Только эта часть объекта видима (для пользователя объекта). Реализационная часть состоит из части данных и процедурной части. Часть данных – это представление (representation ), или состояние объекта, а в процедурной части на некотором языке программирования описывается реализация каждой операции.
Адаптация этого принципа применительно к базам данных состоит в том, что объект инкапсулирует и программу, и данные. В мире баз данных не вполне ясно, является или нет структурная часть типа частью интерфейса (это зависит от системы), в то время как в мире языков программирования структура данных явно является частью реализации, а не интерфейса.
В реляционных системах прикладные программы обычно пишутся на императивном языке программирования с включением в него операторов языка манипулирования данными или на языке четвертого поколения и хранятся в обычной файловой системе, а не в базе данных. Таким образом, при таком подходе имеются кардинальные различия между программой и данными, а также между языком запросов (для незапланированных запросов) и языком программирования (для прикладных программ). 4
В объектно-ориентированных системах имеется единая модель для данных и операций, и информация может быть скрыта.
Никакие иные операции, помимо указанных в интерфейсе, не выполняются. Это ограничение справедливо как для операций изменения, так и для операций выборки.
Инкапсуляция обеспечивает что-то вроде “логической независимости данных”: можно изменить реализацию типа, не меняя каких-либо программ, использующих этот тип. Таким образом, прикладные программы защищены от реализационных изменений на нижних слоях системы.
По мнению авторов Первого манифеста, правильной инкапсуляцией является такая, когда видны только операции, а данные и реализация операций скрыты в объектах. Однако имеются случаи, когда инкапсуляция не нужна, и использование системы может быть значительно упрощено, если система допускает нарушение инкапсуляции при некоторых условиях. Например, при незапланированных запросах инкапсуляция является не столь необходимой, так как такие вопросы, как сопровождаемость, в этом случае не являются важными. Таким образом, ООСБД должна обеспечивать механизм инкапсуляции, но имеются случаи, когда его принудительное использование неуместно.
ITASCA
Распределенная ООСУБД ITASCA основана на результатах проекта Orion , выполнявшегося в MCC . Разработка серии из трех прототипов завершилась выпуском системы, основанной на архитектуре “много клиентов-много серверов”. Система была доведена до уровня коммерческого продукта начинающей техасской компанией, которая в 1995 г. была приобретена компанией IBEX Corp . ().В распределенной архитектуре ITASCA частные и совместно используемые базы данных разнесены по узлам локальной UNIX -ориентированной сети. Каждой значение данных хранится в одном узле, но централизованное управление отсутствует; все серверы автономны. На каждом сервере поддерживаются кэш страниц и кэш объектов, и каждый сервер множество клиентов с обеспечением мультидоступа на основе блокировок. На клиентах поддерживается только кэш объектов.
Для управления мультидоступом в ITASCA используется двухфазный протокол синхронизационных блокировок с сериализацией транзакций и обнаружением тупиков. Также поддерживаются долгие транзакции на основе перемещения объекта из совместно используемой базы данных в частную базу данных (check -out ). Для обеспечения совместной работы допускается участие нескольких пользователей в одной долгой транзакции.
Для всей распределенной базы данных поддерживается единая схема с использование подсхем для частных фрагментов базы данных. Модель данных включает следующие аспекты:
множественное наследование;
представление классов в виде объектов;
наличие свойств и операций классов;
наличие свойств и операций классов;
поддержка ограничений целостности;
возможность перегрузки операций.
В любое время могут добавляться новые данные, классы, свойства и операции. Для обеспечения контроля над распространением таких операций как удаление объекта имеется возможность определения составных объектов. Для поддержки мультимедийных приложений имеется возможность использования линейных массивных объектов, которые предназначены прежде всего для хранения последовательных данных, таких как текст или аудиоданные.
В пространственных массивных объектах имеются два измерения, и они подходят, например, для хранения изображений.
Восстановление базы данных после сбоев производится на основе журнала, предназначенного для аннулирования результата выполненных операций (undo log ). Это позволяет в процессе восстановления устранить эффект всех транзакций, не завершившихся к моменту сбоя. Фиксация транзакции заключается в том, что на сервере все объекты, измененные данной транзакцией, перемещаются из буфера объектов в буфер страниц.
Поддерживается механизм индексирования, основанный на использовании техники B +-деревьев. Можно создавать индексы для одного класса и одного свойства или для нескольких свойств нескольких классов.
Имеется возможность создания классов, поддерживающих оповещение. Имеются две формы оповещения – пассивная и активная. Пассивное оповещение состоит в том, что сохраняется информация о модификации или удалении экземпляров класса. Приложение может обратиться классу с запросом данных о таких событиях. Активное оповещение приводит к вызову некоторой операции при выполнении операций модификации, удаления, создания версии, перемещения объекта из общей базы данных в частную базу данных (check -out ) или наоборот (check -in ). По умолчанию выполнение операции оповещения приводит к отправке электронной почты привилегированному пользователю (администратору системы), но допускается замена поведения этой операции.
Допускается создание временной, рабочей или “выпускной” версии объекта. Для динамического или статического связывания разных версий поддерживается иерархия происхождения версий. При использовании динамического связывания версий иерархия автоматически модифицируется при создании новых версий.
Безопасность данных обеспечивается на основе механизма авторизации доступа, в котором конкретная привилегия (доступ по чтению, доступ по записи или создание) предоставляется роли, за которой может стоять один пользователь или группа пользователей. Привилегии могут быть подсоединены к базам данных, классам, экстентам, объектам, операциям и свойствам.
Имеется авторизация по умолчанию, которая подразумевается для любой роли и может быть дополнена явной авторизацией, положительной (с добавлением привилегий) или отрицательной (с изъятием привилегии).
При использовании C ++ стабильность достигается путем доступа к библиотеке классов, поддерживающих стабильность. В CLOS (Common Lisp Object System ) обеспечивается метакласс стабильности. Стабильные объекты должны быть экземплярами классов, являющихся экземплярами этого метакласса. Кроме того, можно указать, что некоторые свойства стабильного класса являются недолговечными.
В ITASCA поддерживаются C , C ++, Smalltalk , CLOS . Акцент делается на возможности динамического изменения схемы без остановки действия системы и без потребности в массовой повторной компиляции и редактирования связей. Доступ к программам на каждом из языков производится через функциональный API . В случае использования C ++ автоматически создается файл заголовков, который сливается с исходными файлами программного кода при генерации приложения.
Собственный механизм запросов ITASCA позволяет запрашивать данные в частной базе данных, общей базе данных или сразу в обеих базах данных. Для повышения производительности применяются оптимизация запросов и методы распараллеливания.
Язык определения объектов ODL
ODL является языком определения данных для объектной модели ODMG 27. ODL используется исключительно для описания интерфейсов типов приложения, а не для программирования реализации. Это не язык программирования, а всего лишь язык описания схем баз данных.“Программа” на языке ODL – это набор определений типов, констант, исключительных ситуаций, интерфейсов типов и модулей. Не углубляясь в детали и не приводя синтаксических правил, остановимся на наиболее интересных (с точки зрения автора этой статьи) особенностях ODL.
Язык обеспечивает исключительно мощные возможности для определения литеральных типов. С точки зрения автора, наиболее интересны типы коллекций. Можно определить четыре разновидности типов коллекций. Типы категории set – это обычные типы множеств. Типы категории bag – эти типы мультимножеств (в значениях которых допускается наличие элементов-дубликатов). Значениями типов категории list являются упорядоченные списки значений (среди них допускаются дубликаты). Наконец, значениями типы dictionary являются множества пар <ключ, значение> , причем все ключи в этих парах должны быть различными. Определения типов имеют рекурсивную природу. Например, можно определить тип множества структур, элементами которых будут являться списки мультимножеств и т.д.
Синтаксические правила, относящиеся к определению объектных типов, требуют достаточно подробных разъяснений. К сожалению, в стандарте ODMG 3.0 этих разъяснений явно недостаточно. Поэтому дальнейший текст этого пункта является некоторым домыслом автора этой статьи, который логичен, но не обязательно соответствует истинным взглядам авторов стандарта (проверить это не представляется возможным).28
Во-первых, объектный тип можно определить с помощью двух разных синтаксических конструкций языка ODL – interface и class
29. Определение класса отличается от определения интерфейса наличием двух необязательных разделов: extends и type _ property _ list . В действительности, наиболее важным отличием класса от интерфейса является возможность наличия второго из этих разделов.
В списке свойств30 могут присутствовать элементы extent и key . В спецификации модели данных ODMG 3.0 (хотя это и не отражается явно в синтаксисе ODL ) говорится, что для каждого класса может быть определен только один экстент, являющийся множеством всех объектов этого класса, которые после создания должны сохраняться в базе данных.31
Ключ – это набор свойств объектного класса, однозначно идентифицирующий состояние каждого объекта, входящего в экстент класса (это аналог возможного ключа реляционной модели данных). Для класса может быть объявлено несколько ключей, а может не быть объявлено ни одного ключа даже при наличии определения экстента. В последнем случае в экстенте класса могут существовать разные объекты с одним и тем же состоянием.32

Рис. 2.3. Пример иерархии объектных типов и их экстентов
Далее, хотя и интерфейсы, и классы являются средствами определения объектных типов, между ними проводится жесткое различие. Допускается создание объектов только тех объектных типов, которые определены как классы. Объектные типы, определенные как интерфейсы, могут использоваться только для порождения новых объектных типов (интерфейсов и классов) на основании (вообще говоря) множественного наследования. Классы могут определяться на основе (вообще говоря) множественного наследования интерфейсов и одиночного наследования классов.
Механизм наследования от интерфейсов называется в ODMG наследованием IS - A, а механизм наследования от классов – extends . Прежде чем попытаться пояснить этот подход, приведем пример графа наследования интерфейсов и классов, в котором также показывается место существующих экстентов и объектов (рис. 2.3).
На рис. 2.3 “жирными” стрелками показаны связи объектных типов по наследованию IS - A . Обычные стрелки показывают связи по наследованию extends . Пунктирные стрелки соответствуют связям экстентов и соответствующих классов. Обратите внимание, что на этом рисунке у каждого из классов, входящих в иерархию, определен свой собственный экстент.
Как демонстрирует рисунок, в модели ODMG поддерживается семантика включения, означающая, что экстент любого подкласса является подмножеством экстента любого своего суперкласса (прямого или косвенного). Если у некоторого подкласса свой собственный экстент не определен, то с объектами этого подкласса можно работать только через экстент какого-либо суперкласса. Стандарт не требует обязательного определения экстента. В этом случае ответственность на поддержку работы с множествами объектов ложится на прикладного программиста (для этого можно использовать типы коллекций).
Итак, при порождении подкласса путем наследования extends от некоторого суперкласса подкласс наследует экстент и набор ключей суперкласса. Как мы уже заметили, для подкласса можно определить свой собственный экстент. Что же касается возможности переопределения ключей, то в стандарте отсутствуют явные указания о возможности или невозможности этого действия. Однако очевидно, что если бы было разрешено полное переопределение набора ключей для экстента подкласса, то это противоречило бы семантике включения. По мнению автора данной статьи, по этому поводу можно трактовать ODL одним из двух способов:
(1) Если в некотором подклассе определен набор ключей, то в любом его подклассе определение ключей запрещается.
(2) Если в некотором подклассе определен набор ключей, то определение ключей в любом его подклассе приводит к расширению для этого подкласса набора ключей суперкласса.
Теперь немного поговорим о связях. Связи определяются между объектными типами. В модели ODMG поддерживаются только бинарные связи, т.е. связи между двумя типами. Связи могут быть разновидностей “один-к-одному”, “один-ко-многим” и “многие-ко-многим” в зависимости от того, сколько экземпляров соответствующего объектного типа может участвовать в связи.
Связи явно определяются путем указания путей обхода (traversal paths ). Пути обхода указываются парами, по одному пути для каждого направления обхода связи33. Например, в базе данных “служащие-отделы-проекты” служащий работает (works ) в одном отделе, а отдел состоит (consists of ) множества служащих.
Тогда путь обхода consists _ of должен быть определен в объектном типе DEPT , а путь обхода works – в типе EMP . Тот факт, что пути обхода относятся к одной связи, указывается в разделе inverse обоих объявлений пути обхода. В нашем случае определения типов DEPT и EMP могли бы выглядеть следующим образом:
class DEPT {
...
relationship set
inverse EMP :: works
... }
class EMP {
...
relationship DEPT works
inverse DEPT :: consists_of
... }
Как видно, это связь “один-ко-многим”. Путь обходаconsists _ of ассоциирует экземпляр типа DEPT со множеством экземпляров типа EMP , а путь обхода works ассоциирует экземпляр типа EMP с экземпляром типа DEPT . Пути обхода, ведущие к коллекциям объектов, могут быть упорядоченными или неупорядоченными в зависимости от вида коллекции, указанному в объявлении пути обхода. В приведенном выше примере consists _ of является неупорядоченным путем обхода.
В ООСУБД, соответствующей стандарту ODMG , должна поддерживаться ссылочная целостность связей. Это означает, что при ликвидации любого объекта, участвующего в связи, должны ликвидироваться и все пути обхода, ведущие к этому объекту. Такой подход гарантирует, что приложения не смогут воспользоваться путями обхода, ведущими к несуществующим объектам.
Наконец, хотя это явно не отражено в синтаксисе языка ODL (по непонятным для меня причинам), наряду с набором генераторов литеральных типов коллекций set < b>t > , bag < t > , list < t > , array < t > и dictionary < t , v > поддерживается аналогичный набор генераторов объектных типов коллекций – Set < t > , Bag < t > ,List < t > , Array < t > и Dictionary < t , v > . В отличие от литералов-коллекций объекты-коллекции обладают объектными идентификаторами и свойством изменчивости. Во всех случаях требуется, чтобы все элементы коллекции были одного типа, литерального или объектного. И для литеральных, и для объектных коллекций поддерживается возможность итерации
коллекции с перебором элементов коллекции либо в порядке, определяемом системой (для множеств и мультимножеств), либо в порядке, предполагаемом видом коллекции (для списков, массивов и словарей).
Краткая характеристика языка запросов OQL
В кратком и неформальном описании языка мы будем по возможности строго следовать манере и последовательности изложения, принятым в стандарте ODMG 3.0, меняя только примеры.Разработчики языка основывались на следующих основных принципах:
Множественное наследование
Обеспечение или не обеспечение системой множественного наследования не является обязательным. Поскольку сообщество специалистов в области объектно-ориентированного подхода еще не достигло согласия относительно множественного наследования13, обеспечение такого наследования считается необязательным. В случае принятия решения о поддержке множественного наследования предстоит выбор из множества возможных решений проблемы разрешения конфликтов.Немного истории
В начале 80-х гг. осознание полезности объектно-ориентированного подхода применительно к логической организации баз данных привело к тому, что многие исследователи приступили к созданию ООСУБД. В ранних проектах ООСУБД участвовали группы из университетов и исследовательских институтов, ведущих компьютерных компаний и небольших начинающих компаний.Университетские исследовательские группы внесли огромный вклад в развитие технологии баз данных, и не только в области реляционных систем. Многие университетские исследователи с энтузиазмом приняли объектно-ориентированный подход, особенно в применении к области человеко-машинных взаимодействий. К наиболее успешным проектам, в которых производились исследования с целью объединения объектно-ориентированного подхода с технологией баз данных, можно отнести следующие:
Encore в Брауновском университете (Broun University );
Cactis в Колорадском университете (University of Colorado at Boulder);
Thor в Массачусетском технологическом институте (MIT );
Exodus в Висконсинском университете (University of Wisconsin );
Pisa в университетах Глазго и Св. Эндрю (Universities of Glasgo and St. Andrew).
Среди исследовательских институтов, в которых существовали мощные группы, ориентированные на исследования в области объектно-ориентированных баз данных, входили OGI (Oregon Graduate Institute ), MCC (Microelectronics and Computer Technology Corporation ) и французский исследовательский центр INRIA . На базе исследований OGI была создана ООСУБД Gemstone ; исследования, проводившиеся в MCC , привели к созданию ООСУБД Itasca и UniSQL ; в результате исследовательского проекта Altair , выполнявшегося в INRIA , появилась ООСУБД O 2.
Среди наиболее значительных прототипов ООСУБД, созданных в результате исследований, которые проводились в ведущих компьютерных компаниях, можно выделить систему IRIS компании Hewlett -Packard и систему Trellis компании DEC . Идеи и методы, заложенные в этих проектах, были впоследствии использованы в большинстве коммерческих ООСУБД.
Тем не менее, руководители крупных компаний решили не производить коммерческие ООСУБД самостоятельно, а предоставить эту возможность начинающим компаниям.
Первыми компаниями, выпустившими на рынок ООСУБД в виде законченных продуктов, были следующие компании:
Grapael сООСУБД G-Base (1986 г);
Servio-Logic сООСУБД Gemstone (1987 г.);
Symbolics сООСУБД Statice (1988 г.);
Ontologic Ltd. сООСУБД Vbase (1988 г.).
Ко всем ранним реализациям ООСУБД применительны следующие замечания.
Системы были почти неприменимы для практического использования, поскольку они очень медленно работали, поддерживали только однопользовательский режим работы и были крайне ненадежны. В них не поддерживались распределенные данные, безопасность и возможность восстановления после сбоев. Почти во всех системах отсутствовали развитые механизмы формулировки запросов. При построении пользовательских интерфейсов не использовались даже уже имевшиеся результаты, полученные группами из области человеко-машинных взаимодействий.
Разработчики практически всех систем полностью игнорировали язык C ++, поскольку считалось, что применение этого языка в контексте ООСУБД вызывает серьезные проблемы. В системах G -Base и Statice использовался Lisp ; Gemstone опиралась на Smalltalk ; для Vbase были разработаны собственные языки определения данных (TDL ) и манипулирования данными (COP ). В исследовательских группах также предпочитали не опираться на C ++, а разрабатывать новые языки, в большей степени соответствующие направлению исследований. Среди отрицательных последствий игнорирования C ++ было то, что пользователей заставляли изучать новый язык; они вынуждались одновременно использовать два языка; отсутствие поддержки C ++ ограничивало рынок ООСУБД.
Новые компании Objectivity , Object Design и Versant , образованные в конце 80-х, ориентировались на создание ООСУБД, которые опирались бы на C ++. Компания Ontologic отказалась от развития Vbase и переключилась на разработку системы ONTOS , основанной на C ++.
В Европе были образованы компании O 2Technology и BKS Software . Задачей первой компании было создание коммерческой ООСУБД O2 49 на основе результатов проекта Altair . BKS начала разработку системы POET . В 90-е годы для реализации коммерческих проектов, основанных на результатах MCC , были образованы компании UniSQL 50 и Itasca .
К концу 90-х существовало около десяти компаний, производящих коммерческие продукты, позиционируемые на рынке как ООСУБД. Каждый продукт обладал индивидуальными особенностями, частично определяемыми жизненным опытом разработчиков, но большей частью проистекающими из требований клиентов компании. Далее в этом подразделе мы кратко охарактеризуем наиболее известные коммерческие ООСУБД, а в заключение подраздела опишем современное состояние дел в области ООСУБД (которое, по мнению автора, является совсем не блестящим).
Необязательные возможности: конфетки
Под этим заголовком собраны возможности, которые улучшают систему, но не являются обязательными для того, чтобы система была объектно-ориентированной системой баз данных. Некоторые из этих возможностей являются объектно-ориентированными по своей природе (например, множественное наследование12). Они отнесены к категории необязательных возможностей, потому что не входят в набор ключевых требований, хотя и делают систему более объектно-ориентированной.Другие возможности являются просто возможностями систем баз данных (например, управление проектными транзакциями). Эти характеристики обычно улучшают функциональные возможности систем баз данных, но не относятся к ключевым требованиям, предъявляемым к таким системам, и они не связаны с аспектом объектной ориентированности. В действительности, многие из этих возможностей предназначены для обслуживания “новых” приложений (CAD /CAM , CASE , офисная автоматизация и т.д.) и являются более ориентированными на приложения, чем на технологии. Поскольку многие системы объектно-ориентированных баз данных нацелены на эти новые приложения, то существует некоторая путаница между этими возможностями и объектно-ориентированной природой системы.
Неопределенные значения
Поддержка неопределенных значений является одной из наиболее запутанных проблем современной технологии баз данных. Автору данной статьи неизвестно какое-либо удовлетворительное решение проблемы. ODMG тщательно обходит проблему неопределенных значений и пытается свести ее к проблеме неопределенных идентификаторов объектов.39 Опишем подход ODMG с минимальными комментариями.Результатом выборки свойства объекта с пустым идентификатором является специальное значение UNDEFINED . В OQL UNDEFINED считается специальным литеральным значением, входящим во множество значений любого литерального или объектного типа.40
Правила обращения со значением UNDEFINED состоят в следующем:
Результатом операции is _ undefined ( UNDEFINED ) является логическое значение true . Результатом операции is _ defined ( UNDEFINED ) является логическое значение false .
Если при вычислении предиката раздела WHERE OQL -запроса получается значение UNDEFINED , то оно трактуется таким же образом, если бы результатом было значение false .
UNDEFINED является допустимым элементом любой явно или неявно конструируемой коллекции.41
UNDEFINED является допустимым выражением при вычислении агрегатной функции COUNT .42
Результатом любой другой операции, включающей хотя бы один операнд со значением UNDEFINED , является UNDEFINED . 43
Пример 2.11. Найти номера отделов всех сотрудников.
SELECT E.WORKS.DEPT_NO
FROM EMPLOYEES E
Результатом запроса будет мультимножество литералов, среди которых будет содержаться значение UNDEFINED для всех сотрудников, не прикрепленных к какому-либо отделу.
Пример 2.11. Найти всех сотрудников, прикрепленных к какому-либо отделу.
SELECT E
FROM EMPLOYEES E
WHERE is_defined (E.WORKS.DEPT_NO)
Такой же результат был бы выдан при выполнении запроса
SELECT E
FROM EMPLOYEES E
WHERE E.WORKS != nil
Объектно-ориентированные базы данных в стандарте ODMG
Первый манифест формально являлся всего лишь статьей, представленной на Конференцию по объектно-ориентированным и дедуктивным базам данных группой частных лиц. Как вы могли видеть в предыдущем подразделе, требования Манифеста были скорее эмоциональными, чем явно специфицированными. В 1991 г. был образован консорциум ODMG (тогда эта аббревиатура раскрывалась как Object Database Management Group , но впоследствии приобрела более широкую трактовку – Object Data Management Group ). Консорциум ODMG тесно связан с гораздо более многочисленным консорциумом OMG (Object Management Group ), который был образован двумя годами раньше. Основной исходной целью ODMG была выработка промышленного стандарта объектно-ориентированных баз данных (общей модели). За основу была принята базовая объектная модель OMG COM (Core Object Model ). В течение более чем десятилетнего существования ODMG опубликовала три базовых версии стандарта, последняя из которых называется ODMG 3.0 [5]. 16Забавно, что хотя ODMG (по мнению автора) вышла из OMG , в последние годы некоторые стандарты OMG опираются на объектную модель ODMG . В частности, на модель ODMG опирается спецификация языка OCL (Object Constraint Language ), являющаяся частью общей спецификации языка UML 1.4 (и UML 2.0) [7]. В этой статье мы не ставим цель провести детальное сопоставление подходов OMG и ODMG и отсылаем заинтересованных читателей к Энциклопедии Когаловского [6] и материалам сайтов этих консорциумов [7-8]. Мы ограничимся кратким изложением основных идей, содержащихся в стандарте ODMG -3.
Объектно-ориентированные СУБД
В последнем подразделе этого раздела мы обсудим специфические черты наиболее известных и распространенных в мире ООСУБД. Трудно гарантировать, что это обсуждение полностью соответствует текущему положению дел, поскольку ситуация изменяется очень быстро, и то, что пишется сегодня и полностью отвечает истинному положению дел, может оказаться не совсем (или совсем не) верным завтра. Но, тем не менее, мы считаем, что такой подраздел должен присутствовать в разделе про Первый манифест, чтобы показать читателям реальное (или близкое к реальному) состояние дел в соответствующей области информационной технологии.Объектные и литеральные типы
В модели ODMG база данных представляет собой коллекцию различимых значений (denotable values ) двух видов – объекты и литералы. Объекты обладают свойствами идентифицируемости и индивидуального существования, а литералы являются компонентами объектов. Модель данных содержит конструкции для спецификации объектных и литеральных типов. Объектные типы существуют в иерархии объектных типов; литеральные типы похожи на типы, характерные для обычных языков программирования (например, С или Pascal ). В модели ODMG не используется термин класс. Единственная классификационная конструкция называется типом, и типы описывают как объекты, так и литералы. То, что называлось классом в Первом манифесте, в ODMG называется объектным типом.В модели поддерживается ряд литеральных типов – базовые скалярные числовые типы, символьные и булевские типы (атомарные литералы), конструируемые типы литеральных записей (структур) и коллекций. Конструируемые литеральные типы могут основываться на любом литеральном или объектном типе, но считаются неизменчивыми. Даты и время строятся как литеральные структуры. Подробнее о литеральных типах см. в следующем подразделе.
Объектный тип состоит из интерфейса и одной или нескольких реализаций.25 Интерфейс описывает внешний вид типа: какими свойствами он обладает, какие в нем доступны операции и каковы параметры у этих операций.26 В реализации определяются структуры данных, реализующие свойства, и программный код, реализующий операции. Интерфейс составляет общедоступную (public ) часть типа, а в реализации при необходимости могут вводиться дополнительные частные (private ) свойства и операции. Все объектные типы (системные или определяемые пользователем) образуют решетку (lattice ) типов, в корне которой находится предопределенный объектный тип Object . Чтобы не объяснять подробно, что такое решетка, приведем пример графа, являющегося решеткой (рис. 2.2).

Рис. 2.2. Пример ориентированного графа, являющегося решеткой
Поскольку для определения реализации объектного типа требуется использовать один из языков OML , которые мы в этой статье не обсуждаем, ограничимся рассмотрением интерфейсной части типа.
Интерфейс объектного типа состоит их следующих компонентов:
Атрибуты и связи совместно называются свойствами, а свойства и операции совместно называются характеристиками объектного типа (или объектов данного типа).
Точно так же, как имеются атомарные и конструируемые литеральные типы, существуют атомарные и конструируемые объектные типы. В стандарте ODMG 3.0 говорится, что атомарными объектными типа являются только типы, определяемые пользователями (см. ниже).. Конструируемые объектные типы включают структурные типы и набор типов коллекций.
Объекты и литералы
Как утверждалось в Первом манифесте, одним из важнейших отличий объектов от значений является наличие у объекта уникального идентификатора (объекты обладают свойством идентифицируемости). Накладные расходы, требуемые для обращения к объекту по его идентификатору с целью получения доступа к базовым значениям данных, могут весьма сильно замедлить работу приложений. Поэтому в модели ODMG допускается описание всех данных в терминах объектов и использование традиционного вида значений, которые в модели называются литеральными значениями. Таким образом, возраст человека может задаваться целочисленным литералом, а не объектом, имеющим свойство21 возраст. В этом случае значение возраста будет сохраняться как часть структуры данных объекта человек, а не в отдельном объекте. Это, в частности, означает, что объект может входить в состав нескольких других объектов, а литерал – нет. Схема базы данных в модели ODMG главным образом состоит из набора объектных типов, но компонентами этих типов могут быть типы литеральных значений.Другим понятием, используемым для различения объектов и литералов, является понятие изменчивости (mutability ). Предположим, например, что данные о человеке составляют структуру <имя, возраст, адрес_проживания> . Тогда возможны два варианта хранения этих данных:
Другими словами, объект идентифицируется своим объектным идентификатором (OID – Object Identifier ), который полностью отделен от значений компонентов объекта, а литерал полностью идентифицируется значениями своих компонентов.
Объекты как результаты запросов
В примерах предыдущего пункта результатами запросов являлись литеральные значения, не обладающие объектными идентификаторами. Если ввести следующие определения объектных типов:typedef Set
class persinfo {
attribute string <20> n;
attribute date b; };
typedef Bag
то можно сформулировать следующие запросы.
Пример 2.5
ages ( SELECT DISTINCT E.age
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00 )
Окончательным результатом этого запроса является объект-множество, включающий литеральные значения типа interval . 37
Пример 2.6
info ( SELECT persinfo (n: E.EMP_NAME, b: E.EMP_BDATE)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00 )
В этом примере по литеральным значениям имени и даты рождения каждого служащего, размер зарплаты которого превышает 20000 руб., конструируется объект типа persinfo , а на основе литерального мультимножества этих объектов конструируется объект-мультимножество типа info .
В совокупности результатом допустимых в OQL выражений запросов могут являться:
Обязательные свойства: золотые правила
Система объектно-ориентированных баз данных должна удовлетворять двум критериям: она должна быть СУБД и при этом являться объектно-ориентированной системой, т.е. в максимально возможной степени находиться на уровне современных объектно-ориентированных языков программирования. Первый критерий включает пять свойств: стабильность, управление вторичной памятью, параллелизм, восстанавливаемость и средства обеспечения незапланированных (ad hoc ) запросов. Второй опирается на восемь свойств: сложные объекты, идентифицируемость объектов, инкапсуляция, типы или классы, наследование, перекрытие методов совместно с поздним связыванием, расширяемость и вычислительная полнота.Objectivity /DB
Компания Objectivity (http://www.objectivity.com ) была образована в 1988 г. В 1990 г. была выпущена первая версия системы, которая представляла собой распределенную СУБД, основанную на использовании объектной технологии, высокопропускных локальных сетей и симметричных мультипроцессоров. Система работает на всех основных UNIX -платформах и в среде Windows .Система основана на клиент-серверной архитектуре, в которой единицей обмена между сервером и клиентом является страница базы данных. Тем самым многие системные функции, включая кэширование, поиск объектов и преобразование их форматов, выполняются на стороне клиента. Объектные идентификаторы представляются в 64-разрядном формате, что обеспечивает потенциальную возможность работы со сверхбольшими базами данных.
Поддерживается четырехуровневая структура хранения данных. Объекты содержатся в контейнерах, каждый из которых представляет собой часть локальной базы данных. Локальные же базы данных могут комбинироваться в федеративную (распределенную) базу данных. Надежность хранения данных поддерживается механизмом репликации.
Обеспечивается возможность изменения классов и автоматического образования новых версий существующих объектов. Поддерживается механизм управления иерархиями версий объектов.
Допускаются как короткие, так и долгие транзакции. Управление короткими транзакциями основано на синхронизационных блокировках и распознавании тупиков. Долгие транзакции и коллективная работа с базами данных основаны на многоверсионности объектов и механизме check -in /check -out .
В системе поддерживаются языки C ++ и Smalltalk , но способы использования языков сильно различаются. Это относится и к механизмам стабильности, и к средствам определения данных. В среде C ++ стабильными являются объекты всех классов, являющихся наследниками специального системного класса. В среде Smalltalk стабильными являются все объекты, достижимые от именованных корневых объектов-словарей. Соответственно, в Smalltalk для удаления объектов используется механизм сборки мусора, а в C ++ – явные операции.
Естественно, базы данных, управляемые Objectivity /DB , основаны на одной объектной модели. Эта модель достаточно близка к модели ODMG и, в частности, включает возможность определения двунаправленных связей. Поддерживается возможность управления составными объектами с распространением на подобъекты операции удаления. Однако способы определения данных в средах C ++ и Smalltalk различаются.
В C ++ включено специальное расширение языка, предназначенное для определения данных. Соответствующие конструкции обрабатываются специальным препроцессором, который генерирует код C ++, содержащий соответствующие обращения к СУБД. В среде Smalltalk схема базы данных определяется как набор классов Smalltalk . Другими словами, при использовании Smalltalk приложения, работающие с базами данных Objectivity /DB , организуются более прозрачным образом, чем в случае C ++.
Имеется поддержка языка SQL /89 и, частично, SQL /92. Реляционный доступ к базам данных, управляемых Objectivity /DB , возможен через интерактивный SQL -ориентированный интерфейс, через имеющийся драйвер ODBC и через API .
ObjectStore
Компания Object Design была основана в 1988 г. с экстренной целью разработать и вывести на рынок ООСУБД, которую стали называть ObjectStore . В конце 90-х у Object Design установились тесные партнерские отношения с IBM , что позволило привлечь к ObjectStore тысячи разработчиков приложений. На основе технологии ObjectStore компанией был разработана одна из первых коммерческих СУБД – Excelon , ориентированная на управление XML -данными. С начала 2003 г. компания является подразделением компании Progress Software (http://www.objectstore.net).ООСУБД ObjectStore основана на архитектуре клиент-сервер, в которой каждый сервер отвечает за регулирование доступа к хранилищу объектов и управляет журнализацией обновлений, блокировками, установкой контрольных точек, разрешением конфликтов по данным, резервированием данных и восстановлением базы данных после сбоев. Каждый сервер поддерживает множество клиентов. В клиентском процессе используется представление данных более высокого уровня, и клиентская часть ObjectStore отвечает за управление коллекциями, выполнение запросов и управление транзакциями.
Серверная часть спроектирована в расчете на использование механизма отображения виртуальной памяти, которая распространяется на всю сеть и может охватывать несколько серверов. Извлекаемые из базы данных объекты могут объединяться в пакеты для передачи по сети, что позволяет снизить объем сетевого трафика. Для сокращения времени доступа в серверах используется техника кластеризации. На каждой клиентской части имеется локальный кэш, в котором сохраняются используемые объекты. Когда объект перемещается в адресное пространство клиента, ссылки на него перерабатываются таким образом, что для каждого к объекту доступа достаточно одной команды компьютера.
Управление мультидоступом основано на использовании прозрачного для пользователя механизма блокировок, включающего возможность блокирования по чтению и по записи. Поддерживаются разные уровни детализации (гранулированности) блокировок от уровня страниц внешней памяти базы данных до конфигураций (указываемых программистом групп объектов).
Надежность хранения данных обеспечивается за счет поддержания журнала произведенных изменений. Подсистема управления транзакциями отвечает за журнализацию всех произведенных изменений на основе протокола WAL (Write Agead Log – упреждающей записи в журнал). Дополнительно поддерживается архивный журнал, в котором авторизованный пользователь может произвести архивное копирование базы данных.
Имеется средство поддержки версий, которое обеспечивает возможность коллективной работы с базами данных на основе механизмов check -in /check -out . На этом подходе основывается поддержка долгих транзакций. Для каждой конфигурации объектов можно создать историю версий, независимую от типов объектов.
В ObjectStore стабильность хранения объектов поддерживается за счет наличия именованных корневых стабильных объектов класса база данных. База данных создается с помощью вызова метода new этого класса. Имеются методы для открытия и закрытия базы данных. Кроме того, в классе содержатся методы для создания стабильных корневых объектов, обычно являющихся коллекциями, в которых размещаются стабильные объекты.
Поддерживаются языки C , C ++ и Smaltalk . Свойство стабильности обеспечивается за счет включения в библиотеку классов специальных системных классов. Имеются классы, поддерживающие коллекции – списки, множества, мультимножества и массивы. Методы этих классов поддерживают выборку объектов из коллекций, вставку и удаление объектов.
Поддерживаются шлюзовые объекты, поддерживающие доступ к реляционным данным, а также инструментальные средства для отображения реляционной схемы в эквивалентное объектно-ориентированное представление. Таким образом, с реляционными базами данных можно работать в интерфейсе ODBC на основе SQL или в собственном интерфейсе ObjectStore .
Однородность
Ведутся жаркие споры о степени однородности таких систем. Является ли тип объектом? Является ли метод объектом? Следует ли эти три понятия рассматривать отдельно? Эту проблему можно рассматривать на трех разных уровнях: уровне реализации, уровне языка программирования и уровне интерфейса.На уровне реализации необходимо решить, будет ли информация о типе храниться как объект или будет реализована некоторая специализированная система. Это тот же самый вопрос, с которым сталкиваются проектировщики систем реляционных баз данных при принятии решения о том, как следует хранить схему – в виде таблицы или некоторым специальным образом. Решение следует принимать с учетом эффективности и простоты реализации. Какое бы ни было принято решение, оно не зависит от решения, принимаемого на более высоком уровне. Что касается объектно-ориентированных систем, то разногласия по поводу того, являются ли типы объектами, сохранились до сих пор. Правильнее сказать, что появилась некоторая каноническая точка зрения (где типы и классы объектами не являются, но сохраняется позиция однородности). По отношению к стандартным SQL -ориентированным базам данных уже не существует сомнений относительно методов сохранения схемы базы данных – в стандарте SQL , начиная с SQL /92, специфицирована структура таблиц (точнее, представлений), описывающих схему базы данных (информационной схемы в терминах SQL ).
На уровне языка программирования вопрос состоит в том, являются ли типы сущностями первого сорта в семантике языка. Споры ведутся главным образом вокруг этого вопроса. По-видимому, имеются различные стили однородности (синтаксический и семантический). Полная однородность на этом уровне также не согласуется со статической проверкой типов. Скорее, победил синтаксический стиль однородности. Как мы уже отмечали, во многих случаях допускаются операции над типами, но это операции времени компиляции (что-то вроде очень развитых средств макрогенерации).
Наконец, на уровне интерфейса требуется принять еще одно независимое решение. Типы, объекты и методы могут быть представлены для пользователя как однородные, если даже в семантике языка программирования они предстают как различные по своей природе понятия. Обратно, они могут быть представлены для пользователя как различные сущности, хотя язык программирования не делает между ними различия. Это решение следует принимать с учетом человеческого фактора. И здесь однородность не получилась. В языках спецификации объектных интерфейсов четко разделяются типы, объекты и методы.
Открытые возможности
Любая система, удовлетворяющая правилам с первого по тринадцатое, заслуживает названия ООСБД. При проектировании такой системы все равно еще остаются возможности выбора. Это степени свободы людей, реализующих ООСБД. Эти характеристики отличаются от обязательных в том смысле, что относительно них научное сообщество еще не достигло согласия. Они отличаются от необязательных возможностей тем, что непонятно, какая из альтернатив является более, а какая менее объектно-ориентированной.Парадигма программирования
Авторы Первого манифеста не видят причины, по которой одной парадигме программирования следует отдать предпочтение перед другой. В качестве парадигмы программирования можно выбрать стиль логического программирования, стиль функционального программирования или стиль императивного программирования. Другим решением может быть независимость системы от стиля программирования и поддержка нескольких парадигм программирования.Параллелизм
Что касается управления параллельным10 взаимодействием с системой нескольких пользователей, то должны обеспечиваться услуги того же уровня, который предоставляют современные системы баз данных. Система должна обеспечивать гармоническое сосуществование пользователей, одновременно работающих с базой данных. Поэтому должно поддерживаться стандартное понятие атомарности последовательности операций и управляемого совместного доступа. По крайней мере, должна обеспечиваться сериализуемость операций, хотя могут быть и менее жесткие альтернативы.Перекрытие, перегрузка и позднее связывание
Имеются случаи, когда желательно иметь одно и то же имя для различных операций. Рассмотрим, например, операцию визуализации: она принимает на входе объект и отображает его на экране. В зависимости от типа объекта используются разные механизмы отображения. Если объект является изображением, то желательно, чтобы оно действительно появилось на экране. Если объект является человеком, то желательно, чтобы в том или ином виде был отображен описывающий человека кортеж. Наконец, если объект является графом, то желательно получить графическое представление. Рассмотрим теперь задачу отображения множества объектов, типы элементов которого не известны во время компиляции.В приложениях, опирающихся на традиционные системы, потребовалось бы три операции: “отобразить растровое изображение”, “отобразить объект типа человек” и “отобразить граф”. В программе проверялся бы тип каждого объекта, входящего во множество, и использовалась бы соответствующая операция отображения. Для этого при программировании нужно знать все возможные типы объектов, которые могут входить в заданное множество, и соответствующие им операции отображения, и использовать их согласованным образом.
В объектно-ориентированной системе операция отображения определяется на уровне типа “объект” (наиболее общий тип в системе). Таким образом, операция отображения имеет единственное имя и может быть одинаковым образом применена к графам, людям и изображениям. Однако реализация операции переопределяется для каждого типа в соответствии с его особенностями (такое переопределение называется перекрытием – overlapping ). В результате три разные программы имеют одно имя “отобразить” (это называется перегрузкой – overloading ). Для отображения множества элементов мы просто применяем операцию отображения к каждому элементу, оставляя за системой выбор соответствующей реализации во время выполнения.
Здесь реализатор типов по-прежнему должен написать то же количество программ. Но прикладному программисту уже не нужно заботиться о трех различных программах.
Первый манифест
В Первом манифесте [1] была предпринята попытка дать определение системам объектно-ориентированных баз данных. Авторы стремились привести описание основных свойств и характеристик, которыми должна обладать система, претендующая на то, чтобы быть квалифицированной как система объектно-ориентированных баз данных. Насколько это удалось, судить вам.Эти характеристики были разделены на три группы:
Манифест рассматривался как отправная точка для дальнейшей дискуссии.
Полиморфизм
Как мы отмечали ранее в этом разделе, в объектной модели ODMG поддерживается семантика включения, т.е. в экстент суперкласса входят объекты экстентов всех его подклассов. Предположим, например, что мы определили класс PROGRAMMERS как наследника класса EMP через EXTENDS . Пусть для программистов меняется семантика метода HIGHER _ PAID (высокооплачиваемым программистом считается тот, кто получает более 30000 руб. в месяц). Тогда в классе PROGRAMMERS этот метод должен быть переопределен (с сохранением сигнатуры).Понятно, что в соответствии с семантикой включения запрос из прим. 2.13 должен распространяться на всех служащих, включая программистов. Но если текущий объект E является объектом класса PROGRAMMERS , то к нему должен применяться переопределенный вариант метода HIGHER _ PAID . Тем самым, в OQL применятся отложенное связывание объектов и методов.
Еще одна возможность, связанная с полиморфизмом и поддерживающаяся в OQL , состоит в том, что пользователь может явно указать конкретный тип подкласса объектов коллекции, а система будет проверять правильность этого указания во время выполнения запроса. Предположим, что в классе PROGRAMMERS определен дополнительный атрибут favorite _ language , значение которого характеризуют “любимый” язык программирования каждого программиста. Кроме того, пусть известно, что в отделе 632 работают только программисты. Тогда возможен следующий запрос.
Пример 2.14. Получить названия любимых языков программирования сотрудников отдела 632.
SELECT DISTINCT ((PROGRAMMERS)E).favorite_language
FROM EMPLOYEES AS E
WHERE E.EMP_NO = 632
Если во время выполнения запроса будет обнаружено, что среди служащих отдела 632 имеются не только программисты, система зафиксирует ошибочную ситуацию.
Композиция операций
OQL является полностью функциональным языком. Если не нарушается система типов, то допускается произвольная композируемость операций. Этот подход отличается от подхода языка SQL , в котором правила композиции операций не являются ортогональными46.
Наличие полной ортогональности правил композиции в OQL позволяет не ограничивать мощность выражений и облегчить общее понимание языка, сохраняя возможность использования SQL -подобного синтаксиса при формулировке наиболее простых запросов.
Среди операций, которые поддерживаются в OQL и еще не упоминались в этом разделе, содержатся “множественные” операции union , intersect и except для всех видов коллекций; операции с кванторами for all и exists ; операции сортировки и группирования (sort и group by ); агрегатные операции count , sum , min , max и avg . Мы не будем подробно обсуждать эти операции47, но приведем пример достаточно сложного запроса, в котором некоторые из операций используются.
Пример 2.15. Найти название отдела, в котором работают служащие, средняя зарплата которых меньше средней зарплаты служащих любого другого отдела (для простоты предположим, что размер средней зарплаты служащих во всех отделах различается).
Будем строить запрос по шагам с использованием конструкции языка OQL define для вычисления промежуточных результатов.
Шаг 1. Построить множество объектов-служащих, для которых известен номер отдела.
define EMPLOYEES_D () AS
SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil
Шаг 2. Сгруппировать служащих с известными номерами отделов по номерам отделов и вычислить размер средней зарплаты для каждого отдела.
DEFINE DEPT_AVG_SAL () AS
SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM EMPLOYEES_D () E
GROUP BY DEPT_NO : E.DEPT_NO
Типомрезультатаэтогозапросаявляетсяbag < struct { integer DEPT_NO; decimal AVG_SAL } > . Операция group by расщепляет множество служащих на разделы (partitions ) в соответствии с критерием группирования (номеру отдела, в котором работает служащий). В разделе SELECT для каждого раздела вычисляется размер средней зарплаты сотрудников.
Шаг 3. Отсортировать полученное мультимножество по значениям атрибута AVG _ SAL .
DEFINE SORTED_DEPT_AVG_SAL () AS
SELECT S FROM DEPT_AVG_SAL () AS S ORDER BY S.AVG_SAL
Типомрезультатаявляетсяlist < struct { integer DEPT_NO; decimal AVG_SAL } > .
Шаг 4. Выбрать значение атрибута DEPT _ NO из элемента списка SORTED _ DEPT _ AVG _ SAL с наименьшим значением AVG _ SAL (этот элемент стоит в списке первым).
FIRST (SORTED_DEPT_AVG_SAL ()).DEPT_NO
Если собрать запрос целиком, то мы получим следующую конструкцию:
FIRST (SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM (SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil) AS E
GROUP BY DEPT_NO : E.DEPT_NO
ORDER BY AVG_SAL).DEPT_NO
Проектные транзакции
Для большинства новых приложений модель транзакций бизнес-ориентированной системы баз данных является неудовлетворительной: транзакции могут длиться слишком долго, и обычный критерий сериализуемости не является адекватным. Поэтому во многих ООСБД поддерживаются проектные транзакции (протяженные или вложенные).Проверка и вывод типов
Вопрос о том, в какой степени система должна производить проверку типов во время компиляции, остается открытым, однако чем больше проверок во время компиляции, тем лучше. Оптимальной ситуацией является такая, когда успешно откомпилированная программа не может породить во время выполнения ошибки, связанные с несоответствием типов. Вопрос об объеме вывода типов также остается открытым на усмотрение системного проектировщика: чем больше, тем лучше; идеальной ситуацией является такая, в которой необходимо объявить только базовые типы, а система выводит временные типы.Путевые выражения
Для навигации между подобъектами сложных объектов и по связям между разными объектами в OQL поддерживается специальный вид выражений, называемых путевыми (path expression ). Эти выражения определяются в так называемой точечной нотации (вместо операции “.” можно использовать и операцию “->”). Рассмотрим несколько простых примеров. Предположим, что в классах DEPT и EMP , кроме связи CONSISTS _ OF - WORKS определена еще и связь “один-к-одному” MANAGED _ BY - MANAGER _ OF :class DEPT {
...
relationship EMP managed_by
inverse EMP :: manager_of
... }
class EMP {
...
relationship DEPT manager_of
inverse DEPT :: managed_by
... }
Пример 2.7. Для получения объекта типа EMP , соответствующего менеджеру отдела main _ department достаточно написать выражение
main_department.managed_by
Если же требуется получить имя менеджера отдела main _ department , то можно воспользоваться путевым выражением
main_department.managed_by.EMP_NAME
Пример 2.8. Получить имена всех сотрудников отдела main _ department.
Кажется, что запрос очень похож на предыдущий, и что для него годится выражение
main_department.consists_of.EMP_NAME
Но в данном случае мы имеем связь “один-ко-многим”, и хотя у каждого служащего имеется только одно имя, такие путевые выражения в OQL не допускаются. Правильной формулировкой запроса является следующая:
SELECT E.EMP_NAME
FROM main_department.consists_of AS E
Предикаты и логические операции
В спецификации OQL , как и в стандарте языка SQL , термин предикат обозначает условное выражение, которое может участвовать в запросе. Но семантика похожих на SQL конструкций языка OQL существенно отличается, что мы покажем в следующем примере.
Пример 2.9. Получить номера отделов и имена сотрудников отделов, с размером зарплаты, большим 10000 руб., работающих в отделах с числом сотрудников, большим 40 человек, и со средним размером зарплаты, большим 20000 руб.
SELECT STRUCT (DEPT_NO : D.DEPT_NO, EMP_NAME : E.EMP_NAME )
FROM DEPARTMENTS D,
D.CONSISTS_OF E
WHERE D.DEPT_EMP_NO > 40 AND
AVG (E.EMP_SAL) > 20000.00 AND
E.EMP_SAL > 10000.00
Как следует понимать семантику выполнения данного запроса? Образуется внешний цикл по просмотру объектов экстента DEPARTMENTS . Для каждого из этих объектов по связи CONSISTS _ OF образуется коллекция (в данном случае, множество) объектов, входящих в экстент EMPLOYEES . Тем самым, выполняется неявная факторизация (группирование) экстента EMPLOYEES , в которой инвариантом группы служащих является их общий отдел. По этому поводу в списке выборки и в условии выборки (предикате) разрешается использовать как свойства инварианта группы (в нашем случае, DEPT . DEPT _ NO и DEPT . DEPT _ EMP _ NO ) и индивидуальные свойства членов групп (в нашем случае, EMP . EMP _ NAME и EMP . EMP _ SAL ), так и “агрегатные” свойства группы в целом (в нашем случае, AVG ( EMP . EMP _ SAL ) ). Для каждой группы, образуемой во внешнем цикле, оцениваются условия, характеризующие группу в целом. В просмотр внутреннего цикла допускаются только те группы, для которых результатом вычисления условий “группы” было true . За каждым элементом “отобранной” группы сохраняются свойства ее объекта-инварианта.
Как видно даже из этого примера, предикаты раздела WHERE OQL -запросов могут представлять собой произвольно сложное булевское выражение, в котором простые условия связываются логическими операциями AND, OR и NOT. Очевидно, что этот набор операций является избыточным. Тем не менее, в OQL введены две дополнительные логические операции – ANDTHEN и ORELSE . Если X и Y являются логическими выражениями, то при вычислении выражения X ANDTHEN Y выражение Y вычисляется (и определяет общий результат) в том и только в том случае, когда результатом вычисления выражения X является true . Аналогично, при вычислении выражения X ORELSE Y выражение Y вычисляется (и определяет общий результат) в том и только в том случае, когда результатом вычисления выражения X является false . Другими словами, таблицы истинности операций ANDTHEN и ORELSE полностью совпадают с таблицами истинности операций AND и OR соответственно, но предписывается порядок вычислений.
Стандарт ODMG 3. 0 не обеспечивает подробного обоснования для введения этих операций, однако, по нашему мнению, это как-то связано с желанием остаться в рамках двухзначной логики при возможности наличия неопределенных значений. Вот пример запроса, в предикате которого можно сравнительно осмысленно использовать операцию ANDTHEN .
Пример 2.10. Получить имена служащих и номера их отделов для служащих, работающих в отделах с фондом заработной платы, размер которого превышает 1000000 руб.
SELECT STRUCT (name: E.EMP_NAME, dept: D.DEPT_NO)
FROM EMPLOYEES E,
E.WORKS D
WHERE E.WORKS != nil andthen
D.DEPT_TOTAL_SAL > 1000000.00
38
Кратко затронем тему запросов с соединениями. Должно быть понятно, что введение механизма связей в языки ODL и OQL главным образом связано с желанием отказаться от явных естественных соединений. Тем не менее, может возникнуть потребность в явных соединениях коллекций, объекты или литералы которых связываются по значениям. Вот простой пример.
Пример 2.10. Выбрать всех служащих, у которых имеются однофамильцы.
SELECT DISTINCT E
FROM EMPLOYEES E, EMPLOYEES E1
WHERE E != E1 AND E.EMP_NAME = E1.EMP_NAME
В результате будет образовано литеральное множество, элементами которого являются объекты типа EMP , для которых в экстенте EMPLOYEES имеется хотя бы один иной (с другим объектным идентификатором) объект, с тем же значением свойства EMP _ NAME . Понятно, что этот запрос и по виду, и по семантике выполнения является в чистом виде SQL -запросом (если заменить конструкцию E != E1 наE.EMP_NO <> E1.EMP_NO ).
Распределенность
Ясно, что эта характеристика является ортогональной к объектно-ориентированной природе системы. Система баз данных может быть как распределенной, так и нет.Расширяемость
Система баз данных поставляется с набором предопределенных типов. Эти типы могут при желании использоваться программистами для написания приложений. Набор предопределенных типов должен быть расширяемым в том смысле, что должны иметься средства для определения новых типов и не должно быть различий в использовании системных и определенных пользователем типов. Конечно, способы поддержания системой системных и пользовательских типов могут значительно различаться, но эти различия должны быть невидимыми для приложения и прикладного программиста. Напомним, что определение типов включает определение операций этих типов. Заметим, что требование инкапсуляции подразумевает наличие механизма для определения новых типов. Требование расширяемости усиливает эту возможность, указывая, что вновь созданные типы должны иметь тот же статус, что и существующие. Однако не требуется, чтобы расширяемой была и совокупность конструкторов типов (кортежей, множеств, списков и т. д.).Система представления
Система представления определяется набором атомарных типов и набором конструкторов. Хотя в числе Золотых правил указывается минимальный набор атомарных типов и конструкторов (элементарные типы языков программирования и конструкторы множеств, кортежей и списков), который должен быть доступен для описания представления объектов, этот набор может быть расширен множеством разнообразных способов.Система типов
Остается свобода и в выборе способа формирования типов. Единственным средством формирования типов, наличия которого требуют авторы, является инкапсуляция. Возможны другие формирователи типов, такие как родовые типы, генераторы типов и т.д.Сложные объекты
Сложные объекты строятся из более простых при помощи конструкторов. Простейшими объектами являются целые числа, символы, символьные строки произвольной длины, булевские переменные и числа с плавающей точкой (можно было бы добавить другие атомарные типы). Имеются различные конструкторы сложных объектов: конструкторы кортежей, множеств, мультимножеств, списков, массивов и т.д. Минимальный набор конструкторов, который должна иметь система, – это конструкторы множеств, списков и кортежей (множества обеспечивают естественный способ представления наборов объектов реального мира; кортежи представляют естественный способ представления свойств сущностей; списки и массивы сохраняют порядок, который имеет место в реальном мире).Конструкторы объектов должны быть ортогональными, т.е. любой конструктор должен быть применим к любому объекту. (Конструкторы реляционной модели не являются ортогональными, потому что конструкция множества может быть применена только к кортежам, а конструкция кортежа – только к атомарным значениям.)
Для поддержки сложных объектов необходимы соответствующие операторы. То есть операции со сложным объектом должны транзитивно распространяться на все его компоненты. Примерами могут быть выборка или удаление сложного объекта целиком или создание “глубокой” копии (в отличие от “поверхностной” копии, в которой компоненты не копируются: в копии корня объекта указываются ссылки на компоненты копируемого объекта).
Средства обеспечения незапланированных запросов
Основной проблемой является обеспечение функциональности языка незапланированных (ad hoc ) запросов. Авторы Первого манифеста не призывают к тому, чтобы эта функциональность обязательно была реализована в виде языка запросов, а требуют только, чтобы была такая услуга существовала. Например, для обеспечения этой функциональной возможности вполне достаточно наличие графической программы просмотра. Услуга состоит в том, что пользователь может без затруднений сделать простой запрос к базе данных.11 Очевидной мерой являются, конечно, реляционные системы. Поэтому проверка наличия средства незапланированных запросов состоит в том, чтобы взять на пробу несколько реляционных запросов и проверить, можно ли их сформулировать с теми же затратами труда. Заметим, что это средство могло бы поддерживаться языком манипулирования данными или его подмножеством.Средство обеспечения запросов должно удовлетворять следующим трем критериям:
Стабильность
Это требование очевидно с точки зрения баз данных, но является новым с точки зрения языков программирования. Стабильность (persistence )9 означает возможность программиста обеспечить сохранность данных после завершения выполнения процесса с целью последующего использования в другом процессе. Свойство стабильности должно быть ортогональным к другим свойствам, т.е. для каждого объекта вне зависимости от его типа должна иметься возможность сделать его стабильным (без какой-либо явной переделки объекта). Стабильность должна быть неявной: пользователь не должен явно перемещать или копировать данные, чтобы сделать их стабильными.Связи
В большинстве объектных систем связи неявно моделируются как свойства, значениями которых являются объекты. Например, если человек работает на некоторую компанию, то у каждого объекта-человека должно иметься свойство, которое можно назвать worksFor и значением которого является соответствующий объект-компания.23 Возникает проблема, если у объекта-компании имеется свойство, которое затрагивает множество служащих этой компании (например, employees – множество, включающее все объекты служащих данной компании). Эти два свойства являются несвязными, и поддержка их согласованности может вызывать значительную программистскую проблему.В модели ODMG , подобно ER -модели, различаются два вида свойств – атрибуты и связи, хотя и несколько другим образом. Атрибутами называются свойства объекта, значение которых можно получить по OID объекта, но не наоборот. Значениями атрибутов могут быть и литералы, и объекты, но только тогда, когда не требуется обратная ссылка. Связи – это инверсные свойства. В этом случае значением свойства может быть только объект, поскольку литеральные значения не обладают свойствами. Поэтому возраст служащего обычно моделируется как атрибут, а компания, в которой работает служащий, – как связь.
При определении связи должна быть определена ее инверсия. В приведенном выше примере, если worksFor определяется как связь, должно быть явно указано, что инверсией является свойство employees объекта-компании, а при определении employees должна быть указана инверсия worksFor . После этого система баз данных должна поддерживать согласованность связанных данных, что позволяет сократить объем работы программистов приложений и повысить надежность их программ.24 Если в объекте-компании свойство employees не требуется, то свойство объекта-служащего employees может быть атрибутом.
Типы и классы
Имеются две основные категории объектно-ориентированных систем, в одной из которых поддерживают классы, а в другой – типы. К первой категории относятся системы, опирающиеся на языки Smalltalk и Lisp . К представителям второй категории относятся, например, C ++ и Simula .В объектно-ориентированной системе в понятии типа обобщаются общие черты множества объектов с одинаковыми характеристиками. Это понятие соответствует понятию абстрактного типа данных. Тип делится на две части – интерфейс и реализация. Пользователям типа видна только интерфейсная часть, а реализация объекта видна только проектировщику типа. Интерфейс состоит из списка операций вместе с их сигнатурами (т.е. набором типов входных параметров и типом результата). Реализация типа состоит из части данных и части операций. Часть данных описывает внутреннюю структуру данных объекта. В зависимости от мощности системы часть данных может быть более или менее сложной. Часть операций состоит из процедур, которые реализуют операции интерфейсной части.
Если система типов достаточно тщательно разработана, то система может произвести проверку типов во время компиляции, иначе некоторые проверки могут быть отложены до времени выполнения. Таким образом, типы главным образом используются во время компиляции для проверки правильности программ. Вообще говоря, в основанных на типах системах тип имеет специальный статус и не может быть изменен во время выполнения.
Понятие класса отличается от понятия типа. Его спецификация совпадает со спецификацией типа, но является более динамическим понятием. Класс характеризуется двумя аспектами: фабрика объектов и склад объектов. Фабрика объектов может быть использована для создания новых объектов посредством выполнения операции new данного класса операции или клонирования некоторого объекта-прототипа, являющегося представителем данного класса. Склад объектов означает, что к классу присоединяется его расширение, т.е. набор объектов, которые являются экземплярами класса. Пользователь может манипулировать складом, применяя операции ко всем экземплярам класса.
Классы используются не для проверки правильности программы, а скорее для создания и манипулирования объектами. В большинстве систем, в которых используется механизм классов, классы обладают таким же статусом, как переменные и значения, ими можно манипулировать во время выполнения программы, т. е. изменять их и передавать как параметры. В большинстве случаев это делает невозможным проверку типов во время компиляции, но придает системе большую гибкость и однородность. Здесь речь идет о так называемых “полнотиповых” языках программирования (баз данных), в которых действительно создается иллюзия, что с типами можно оперировать во время выполнения программы. Насколько известно автору, при реализации, тем не менее, обычно пытаются ограничить операции над типами таким образом, чтобы можно было выполнить эти операции во время компиляции.
Конечно, между классами и типами имеется значительное сходство, оба термина использовались в каждом из значений, а в некоторых системах отличие между ними и вовсе едва заметно. Авторы Первого манифеста не чувствовали себя вправе отдать предпочтение одному из двух подходов и оставляли право выбора за проектировщиком системы. 5
Однако требовалось, чтобы система предоставляла некоторый механизм структурирования данных, будь это классы или типы. Таким образом, классическое понятие схемы базы данных заменяется на понятие множества классов или множества типов.
Авторы не видели необходимости в том, чтобы система автоматически поддерживала экстент типа (т. е. набор объектов данного типа в базе данных) или, если экстент типа поддерживается, чтобы система предоставляла пользователю доступ к нему. Рассмотрим, например, тип “прямоугольник”, который может использоваться в различных базах данных многими пользователями. Не имеет смысла говорить о множестве всех прямоугольников, поддерживаемых системой, или производить операции над ними. Мы думаем, что более оправдано отдать на откуп пользователю поддержку его множества прямоугольников и манипулирование ими.С другой стороны, в случае такого типа как “служащий” весьма удобно, чтобы система автоматически сопровождала экстент этого типа.
Управление вторичной памятью
Управление вторичной памятью является классической чертой систем управления базами данных. Эта возможность обычно поддерживается с помощью набора механизмов. Среди них управление индексами, кластеризация данных, буферизация данных, выбор пути доступа и оптимизация запросов.Ни один из этих механизмов не является видимым для пользователя – это просто средства повышения производительности системы. Однако эти средства настолько важны с точки зрения эффективности, что при их отсутствии система не сможет выполнять некоторые задачи (просто потому, что их выполнение будет занимать слишком много времени). Особо важна невидимость таких средств. Прикладной программист не должен писать программы для сопровождения индексов, распределять память на диске или перемещать данные между диском и основной памятью. Должна обеспечиваться четкая независимость между логическим и физическим уровнями системы.
Versant
С 1988 г. компания Versant (http ://www .versant .com /) предлагает решения, основанные на хорошо масштабируемой объектно-ориентированной архитектуре и принадлежащем компании алгоритме кэширования. ООСУБД Versant является одной из немногих объектно-ориентированных систем, допускающих масштабирование уровня любого предприятия. Решения на базе Vers ant применяются в телекоммуникациях, обороне, на транспорте и т.д. Система работает как на основных UNIX-платформах, так и в среде Windows.Архитектура Versant в большей степени ориентирована на логическое управления данными, т.е. объектами, а не на физическое представление данных в виде, например, страниц. Управление размещением объекта осуществляется системой способом, полностью прозрачным для пользователей. Для поддержки локальных хранилищ объектов используется кэширование.
Система обладает свойством отказоустойчивости. Для этого допускается синхронная репликация базы данных на двух серверах, которые могут находиться в одной локальной сети или разнесены в разные точки глобальной сети. В одной базе данных Versant может храниться около трехсот триллионов объектов, размер каждого из которых неограничен. Для архивации данных может использоваться третичная внешняя память с автоматическим оповещением оператора в случае потребности извлечения объектов из архива.
Поддерживаются кластеры совместно используемых объектов, причем встроенные объекты хранятся внутри своих объектов-предков, что способствует уменьшению уровня фрагментации памяти. Кластеризация применяется и при внешнем кэшировании. Кроме того, в системе Versant поддерживается возможность использования персональных баз данных, установленных на мобильных компьютерах. Они могут быть отсоединены от сервера центральной базы данных, использоваться автономно и зафиксировать свои изменения в центральной базе данных после восстановления соединения.
Управление транзакциями основывается, главным образом, на синхронизационных блокировках на уровне объектов, хотя возможны блокировки классов и версий объектов.
Имеется целый ряд разновидностей блокировок: короткие блокировки для коротких транзакций, стабильные блокировки для долгих транзакций и т.д. Допускается даже возможность расширения модели блокировки правилами, желательными для пользователей. Система избегает тупиковых синхронизационных ситуаций, не удовлетворяя запросы на блокировку, которые могут привести к тупику.
Фиксация распределенных транзакций основывается на двухфазном протоколе фиксации. Поддерживаются частичная фиксация кэшей, механизмы контрольных точек и точек сохранения. Обеспечивается и возможность образования вложенных транзакций. При реализации долгих транзакций используется механизм check -in /check -out с установкой стабильной блокировки на требуемые объекты, предотвращающей доступ к этим объектам со стороны других транзакций до завершения данной долгой транзакции.
Имеется возможность регистрации на сервере событий, которые интересуют приложения. При регистрации серверу сообщается вид события и операция, которую следует выполнять при возникновении события. К событиям, которые разрешается регистрировать, относятся обновление и удаление классов, создание, обновление и удаление объектов.
Для повышения надежности хранения баз данных поддерживаются два вида журналов – логический и физический. При необходимости восстановления базы данных по архивной копии все зафиксированные к моменту сбоя транзакции повторно воспроизводятся по логическому журналу.
Обеспечивается ссылочная целостность базы данных и прозрачность месторасположения объектов в распределенной среде. Объекты могут мигрировать по узлам сети, что способствует балансировке нагрузки, и оставаться полностью доступными для приложений. Допускается динамическая модификация классов, приводящая к автоматической модификации всех существующих в базе данных объектов этих классов. При этом система все время остается в рабочем состоянии, и приложения продолжают выполняться. Поддерживается развитый механизм версий. По известной версии объекта можно получить доступ к его предкам, потомкам и братьям.
Для представления связей между объектами базы данных используется единый стабильный указательный тип. В системе поддерживаются скрытые от пользователей преобразования указателей базы данных в обычные указатели C ++ и наоборот. Поэтому объекты создаются и ликвидируются с помощью стандартных конструкторов и деструкторов классов.
Для программирования можно использовать языки C ++ и Smalltalk , причем безо всяких расширений. Поддерживаются возможности, специфичные для работы с базами данных. Например, имеется средство автоматической генерации схемы базы данных прямо по файлам заголовков C ++. Это позволяет обойтись без использования специализированных препроцессоров или компиляторов. Специальные системные классы позволяют работать со всеми разновидностями типов коллекций, специфицированными в стандарте ODMG . Любой объект, созданный в среде C ++, доступен в среде Smalltalk и наоборот.
Запросы к базам данных Versant можно задавать с помощью специального системного класса, позволяющего обходить объекты коллекций. Поддерживается расширенный вариант SQL /89. Имеется драйвер ODBC . Обеспечивается доступ из среды Versant к внешним реляционным базам данных.
Версии
Большинство новых приложений (CAD /CAM и CASE ) включают проектную деятельность и требуют поддержки версий в том или ином виде. Поэтому во многих ООСБД поддерживаются версии. И в этом случае обеспечение механизма поддержки версий не является ключевым требованием к системе.Входные данные и результаты запросов
Как утверждается в стандарте ODMG 3.0, “OQL -запрос является функцией, вырабатывающей объект, тип которого может быть выведен на основе операций, которые участвуют в выражении запроса”.34
Вот несколько примеров простых OQL -запросов (мы будем использовать в этих примерах определенные в предыдущем подразделе классы DEPT и EMP в предположении, что DEPARTMENTS и EMPLOYEES являются именами экстентов этих классов).
Пример 2.1. Найти даты рождения служащих, зарплата которых превышает 20000 руб.
SELECT DISTINCT E.EMP_BDATE
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
Легко видеть, что этот запрос по своему виду ничем не отличается от соответствующего запроса к таблице EMP , выраженного на языке SQL . В данном случае результатом запроса будет литеральное значение типа set < date > , т.е. литеральное значение-множество, элементами которого являются значения типа date.
Пример 2.2. Найти имена и даты рождения служащих, зарплата которых превышает 20000 руб.
SELECT DISTINCT STRUCT (name: E.EMP_NAME, bdate: E.EMP_BDATE)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
Запрос снова очень похож на соответствующий запрос на языке SQL, а результатом запроса является литеральное значение-множество, элементами которого являются значения типа struct { string <20> name ; date bdate }. Наверное, для конечного пользователя языка OQL строгий вывод типа результата запроса может показаться избыточным, но для программистов приложений это свойство является очень важным.
Если предположить, что в классе EMP определена операция age , значением которой является возраст соответствующего служащего, то результатом запроса
SELECT DISTINCT STRUCT (name: E.EMP_NAME, age: E.age)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
будет литеральное значение-множество, элементами которого являются значения типа struct { string <20> name ; interval age } (пример 2.2a ).
Пример 2.3. Получить номера менеджеров отделов и тех сотрудников их отделов, зарплата которых превышает 20000 руб.
SELECT DISTINCT STRUCT ( mng: D.DEPT_MNG,
DHS: ( SELECT E
FROM D.CONSISTS_OF AS E
WHERE E.EMP_SAL > 20000.00 ) )
FROM DEPARTMENTS D
Внешне этот запрос снова похож на SQL -запрос со вложенным подзапросом, но это только внешнее сходство. Во-первых, в разделе FROM “подзапроса” мы имеем дело с переходом по связи CONSISTS _ OF от экземпляра объектного типа DEPT ко множеству экземпляров объектного типа EMP . Во-вторых, результатом запроса является литеральное значение-множество, элементами которого являются значения-структуры с двумя литеральными значениями, первое из которых есть атомарное литеральное значение типа INTEGER , а второе – литеральное значение-множество с элементами-объектами типа EMP. Более точно, результат запроса имеет тип set < struct { integer mng ; bag < EMP > DHS } >. Конечно, в “классическом” SQL такого быть не может, хотя в следующем разделе мы обсудим возможности объектно-реляционных расширений этого языка.
В OQL предполагается, что хранимые в базе данных объекты могут иметь индивидуальные имена. 35
Пример 2.4. Если, например, в базе данных сохраняется объект типа DEPT с именем main _ department, то результатом запроса
main _ department
будет являться соответствующий объект. Результатом запроса
main_department.CONSISTS_OF
будет литеральное значение-множество, состоящее из объектов типа EMP , ассоциированных через связь CONSISTS _ OF с объектом main _ department
36.
Наконец, в контексте OQL имя каждого экстента можно трактовать как имя объекта-множества. Поэтому результатом запроса
EMPLOYEES
будет литеральное множество, состоящее из всех объектов, которые содержаться в указанном экстенте.
Восстановление
И в этом случае система должна обеспечивать услуги того же уровня, который предоставляют современные системы баз данных. Другими словами, в случае аппаратных или программных сбоев система должна восстанавливаться, т. е. возвращаться к некоторому согласованному состоянию данных. Аппаратные сбои включают как сбои в работе процессора, так и сбои дисков.Введение в объектную модель ODMG
Модель ODMG является объектной моделью данных, включающей возможность описания как объектов, так и литеральных значений. На разработку модели повлиял тот факт, что она предназначена для поддержки работы с базами данных, так что особо важной является эффективность доступа к данным. Большинство других объектных моделей (см. например, матрицу объектных моделей Фрэнка Манолы [9]) ориентировано на языки программирования, расc читанных на работу со всеми данными в основной памяти. В этом случае допустимо представлять все данные как объекты. Но если требуется управлять большим объемом данных, расположенных во внешней памяти, то требуется некоторый компромисс между “чистотой” модели и требуемой эффективностью. Модель ODMG подстраивается под специфику систем баз данных следующим образом:Для баз данных, схем и подсхем обеспечивается набор встроенных объектных типов.
Модель включает ряд встроенных структурных типов, позволяющих применять традиционные методы моделирования баз данных.
Обсудим немного более подробно два последних пункта.
Введение в Первый манифест
Выделялись три характерные черты современного (пятнадцать лет назад!) состояния дел (в области объектно-ориентированных систем баз данных): (а) отсутствие общепринятой модели данных, (б) отсутствие формального базиса и (с) активная экспериментаторская деятельность.В конце 80-х ситуация с реализациями объектно-ориентированных систем управления базами данных (ООСУБД) была аналогична ситуации с РСУБД в середине семидесятых (хотя в случае объектно-ориентированных систем наработок было больше). В случае реляционных систем, хотя и имелись некоторые разногласия по некоторым конкретным вопросам, таким как форма языка запросов, или должны ли отношения быть множествами или мультимножествами, эти различия были в большинстве случаев несущественными 1, и существовала общепринятая основополагающая модель. Люди, главным образом, занимались разработкой технологии реализации. Создатели Первого манифеста одновременно решали проблему спецификации системы и предлагали технологию для поддержки ее реализации.
В отношении спецификации системы было принято решение придерживаться Дарвинистского подхода (эволюционного отбора): существовала надежда, что из множества построенных экспериментальных прототипов сама собой появится подходящая модель. Авторы также надеялись, что одновременно с ней появится жизнеспособная технология реализации этой модели.
При опоре на экспериментаторскую деятельность имеется риск принять в качестве образца некоторую систему не потому, что она является оптимальной, а поскольку она появляется первой среди тех систем, которые обеспечивают значительный набор функциональных возможностей, отвечающих требованиям рынка. Это, к несчастью, типично для компьютерной области: первый продукт становится де-факто стандартом и таковым остается. 2 Такая ситуация существует, по крайней мере, для языков и операционных систем ( Fortran , Lisp , Cobol и SQL представляют хорошие примеры). Однако целью авторов Первого манифеста являлась не стандартизация языков, а уточнение терминологии.
Чрезвычайно важно прийти к согласию об определении систем объектно-ориентированных баз данных. В качестве первого шага к этой цели в Первом манифесте предлагались характеристики, которым должны отвечать такие системы. Авторы выражали надежду, что их труд будет рассматриваться как пробный шар и что другие специалисты либо докажут несостоятельность, либо подтвердят основные положения. Материал не являлся обзором положения дел в технологии объектно-ориентированных систем баз данных (ООСБД) и не претендовал на оценку современного состояния технологии; в нем всего лишь предлагался набор определений.
Характеристики систем объектно-ориентированных баз данных были разделены на три категории: обязательные (те, которым система должна удовлетворять для того, чтобы иметь право называться объектно-ориентированной), необязательные (те, которые могут быть добавлены для улучшения системы, но не являются обязательными) и открытые (те места, где проектировщик может выбрать решение из набора одинаково приемлемых решений). Оставлялась некоторая возможность маневра в том, как лучше сформулировать каждую характеристику (это касается как обязательных, так и необязательных характеристик).
Вычислительная полнота
С точки зрения языка программирования свойство вычислительной полноты является очевидным: оно просто означает, что любую вычислимую функцию можно выразить с помощью языка манипулирования данными системы баз данных. С точки зрения базы данных это является новшеством, так как SQL , например, не является полным языком (напомним, что речь идет про SQL 15-летней давности).Авторы Первого манифеста не призывали проектировщиков объектно-ориентированных систем баз данных к созданию новых языков программирования. Вычислительную полноту можно получить, разумным образом опираясь на существующие языки программирования. Вычислительная полнота – это не то же самое, что “ресурсная полнота”, т.е. возможность доступа ко всем ресурсам системы с использованием внутренних средств языка. Система, даже будучи вычислительно полной, может быть не способна к полной поддержке приложения. Тем не менее, такая система является более мощной, чем система баз данных, которая обеспечивает только хранение и извлечение данных и выполняет простые вычисления с атомарными значениями. Легко заметить, что здесь опять под “плохой” системой понимается SQL -ориентированная СУБД. И последнее утверждение является не вполне справедливым, поскольку уже в SQL /89 обеспечивалась возможность встраивания операторов SQL в вычислительно полные императивные языки, т.е. на основе SQL и некоторого традиционного языка программирования можно было написать законченное приложение.
Вызовы методов
В OQL допускается вызов метода объекта с указанием действительных параметров или без их указания (в зависимости от сигнатуры метода объекта, или класса) в любом месте запроса, если тип результата вызова метода соответствует типу ожидаемого результата запроса. Если у метода отсутствуют параметры, то нотация вызова метода в точности совпадает с нотацией выбора атрибута или перехода по связи. Если у метода имеются параметры, то их действительные значения задаются через запятую в круглых скобках. Этот гибкий синтаксис освобождает пользователя от необходимости знать, является ли свойство хранимым (атрибутом) или вычисляемым (методом).44 Однако, если в классе (или интерфейсе) содержатся одноименные атрибут и метод без параметров, то для разрешения конфликта имен в вызове метода должны содержаться круглые скобки.В примере 2.2a мы уже показывали вариант запроса, содержащего вызов метода. В модели ODMG допускаются методы, вырабатывающие результат в виде сложных объектов или коллекций литеральных значений или объектов. Например, представим себе, что в классе EMP определена операция HIGHER _ PAID , которая для данного объекта-служащего производит множество объектов-служащих того же отдела с большим размером зарплаты. Тогда возможен следующий запрос.
Пример 2.13. Найти названия проектов, в которых участвуют сотрудники отдела 632, получающие зарплату с размером выше среднего.45
SELECT DISTINCT E.HIGHER_PAID.participate_in.PRO_NAME
FROM EMPLOYEES AS E
WHERE E.EMP_NO = 632
Здесь мы предполагаем, что между классами EMP и PRO имеется связь “многие-к-одному” participates _ in - participants _ of (один сотрудник может принимать участие не более чем в одном проекте, но в любом проекте может участвовать произвольное число сотрудников).
Приведенный краткий обзор основных особенностей
Приведенный краткий обзор основных особенностей наиболее популярных коммерческих ООСУБД показывает, прежде всего, очень большую техническую разнородность этих систем. В общем смысле все системы соответствуют базовой модели ODMG , но следует обратить внимание, что крайне редко в качестве языка запросов поддерживается OQL , и ни в одной системе не поддерживается ODL .Ни одна из компаний, производящих ООСУБД, так и не смогла набрать критическую массу, достаточную для того, чтобы стать лидером, диктующим моду в данной области (как это произошло с IBM и Oracle в области SQL -ориентированных СУБД). Крупные компьютерные компании так и не решились приобрести какой-нибудь продукт ООСУБД, чтобы развивать его и продвигать на рынке. Примером является поглощение одной из наиболее известных в мире ООСУБД компании ObjectSystems не самой крупной компьютерной компанией Progress Software . Компания Progress пошла на этот шаг не потому, что ей понадобилось владеть ООСУБД ObjectStore , а только по той причине, что ранее на основе этой СУБД в компании ObjectSystems был создан продукт eXcelon , предназначенный для управления XML -данными.
Когда появился и стал широко распространяться язык Java , казалось, что поддержка этого языка станет сильным козырем ООСУБД. В 1997 г. одна из крупнейших софтверных компаний Computer Associates выпустила на рынок ООСУБД Jasmine , в которой активно поддерживался язык Java . Объявляя о выпуске этого продукта, президент компании заявил, что по его оценкам в течение пяти лет Jasmine войдет в тройку наиболее доходных продуктов Computer Associates . Пять лет прошло, появилось сообщество пользователей Jasmine , но совсем не такое большое, как рассчитывало руководство компании.
[] [] []
document.write('');
|
<
| This Web server launched on February 24, 1997 Copyright © 1997-2000 CIT, © 2001-2009 |
| Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. |
|
Вам: от лидера. |
Заключение к золотым правилам
Приведем те свойства, по поводу которых авторы не достигли согласия, должны ли они быть обязательными или нет. Эти свойства включают следующее:Заключение раздела
Конечно, трудно сравнивать технологию объектно-ориентированных СУБД с технологией SQL -ориентированных систем51. SQL вышел из реляционного подхода к управлению базами данных. Основной идеей являлась максимальная простота логических структур данных, обеспечивающая логическую независимость приложений от используемых ими баз данных. ООСУБД вышли из объектно-ориентированных языков программирования. Основная идея состояла в желании обеспечить хранение в базе данных произвольно сложных структур данных, какие только допускает язык программирования. Эта принципиальная разница в идейной основе подходов неизбежно привела к принципиальному различию в технологиях.В этом разделе мы сначала рассмотрели общие модельные принципы организации ООСУБД, начав с Манифеста объектно-ориентированных баз данных и перейдя затем к стандарту ODMG . Следует заметить, что в целом стандарт ODMG оставляет противоречивые ощущения. С одной стороны, в документе содержится много интересных идей и технических спецификаций. С другой стороны, некоторые важные части стандарта кажутся недостаточно проработанными и плохо отредактированными. Местами встречаются противоречия и прямые ошибки. Но это единственный общепризнанный стандарт ООСУБД, и его полезно знать хотя бы в общих чертах. В конце раздела мы кратко описали черты нескольких известных коммерческих ООСУБД, чтобы показать, что в области ООСУБД отношение производителей к стандартам более анархично, чем в области SQL -ориентированных СУБД.
[] [] []
document.write('');
|
<
| This Web server launched on February 24, 1997 Copyright © 1997-2000 CIT, © 2001-2009 |
| Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. |
|
по всем правилам, с соблюдением стандартов - компания Шторм |
Три манифеста баз данных ретроспектива и перспективы
Активные данные
Под “свойством активности данных” понимается механизм, заставляющий оператор SQL производить некоторые действия, потребность в которых в самом операторе явно не выражена. В DB 2 существуют две категории активных данных - ограничения и триггеры. Ограничения являются декларативными утверждениями, истинность которых контролируется системой. Триггеры - это автоматические действия, которые срабатывают каждый раз при возникновении определенного события или условия.Ограничения представляют собой декларативные правила. Триггер выполняет приказы при возникновении определенных событий. Вот некоторые из возможностей механизма триггеров DB 2:
триггер может быть активизирован при выполнении операций занесения, удаления или модификации строк указанной таблицы или при модификации определенных столбцов таблицы;
можно потребовать срабатывания триггера до или после обработки события, которое его активизирует;
триггер может срабатывать в точности один раз при активизации его оператором SQL или же вызываться для каждой строки, изменяемой оператором SQL;
при активизации триггер может вычислять предикат, называемый “условием триггера”; тогда тело триггера выполняется только если его условие истинно;
тело триггера может состоять из одного или нескольких операторов SQL, в которых могут использоваться специальные переменные, указывающие на значения строки или группы строк до и после активизации триггера; если в тело триггера входят операторы модификации базы данных, то авторизация доступа производится от имени создателя триггера, а не того пользователя, оператор которого активизировал триггер.
это конструктор типов, позволяющий производить
Анонимный строчный тип – это конструктор типов, позволяющий производить безымянные типы строк (кортежей). Любой возможный строчный тип получается путем использования ROW . При определении столбца, значения которого должны принадлежать некоторому строчному типу, используется конструкция ROW ( fld 1 , fld 2 , …, fld n) , где каждый элемент fldi , определяющий поле строчного типа, задается в виде тройки fldname , fldtype , fldoptions . Подэлемент fldname задает имя соответствующего поля строчного типа. Подэлемент fldtype специфицирует тип данных этого поля. В качестве типа данных поля строчного типа можно использовать любой допустимый в SQL тип данных, включая другие строчные типы. Необязательный подэлемент fldoptions может задаваться для указания применяемого по умолчанию порядка сортировки, если соответствующий подэлемент fldtype указывает на тип символьных строк, а также должен задаваться, если fldtype указывает на ссылочный тип (см. ниже). Степенью строчного типа называется число его полей.Дополнительные объектно-реляционные возможности Oracle 9 i
Основные расширения объектно-реляционных возможностей Oracle 8, появившиеся в Oracle 9i , касаются наследования объектных типов и представлений. Эти расширения (в особенности, наследование объектных типов) очень близки к спецификациям SQL :1999.Объектное представление может определяться в виде подпредставления другого объектного представления с порождением иерархии представлений. При этом множество строк любого наследуемого объектного представления включает все строки всех подпредставлений.
Иерархии представлений обладают следующими дополнительными свойствами:
Заметим, что, конечно, механизм наследования представлений, реализованный в Oracle 9i , является гораздо более гибким, чем механизм наследования таблиц в IUS . Понятно также, что при реализации механизма наследования представлений не должны были возникать особые трудности. Но, как кажется автору этой статьи, этот механизм не слишком удобен для использования.
Еще одним новшеством Oracle 9i является возможность определения типов коллекций, тип элементов которых может определяться с использованием других типов коллекций. Примеры соответствующих языковых конструкций слишком громоздки, чтобы приводить их в этой статье.
IBM DB2 Universal Database (UDB)
Компания IBM последней, после Informix и Oracle , объявила свой объектно-реляционный продукт (в конце 1998 г.) и назвала его DB 2 Universal Database (UDB ). Однако, как стало ясно немного позже, базовые идеи объектно-реляционных расширений были заложены еще в продукте компании IBM DB 2 for Common Servers , выпущенном в 1995 г. Эти идеи описаны в замечательной статье Дона Чемберлина [11], и мы начнем с очень изложения этой статьи. После этого мы также кратко обсудим дополнительные объектно-реляционные возможности DB 2, появившиеся после выпуска UDB .Индивидуальные типы
Индивидуальным типом называется UDT , основанный на единственном встроенном типе (например, INTEGER ). Значения такого типа нельзя прямо использовать в операциях соответствующего базового типа, однако допускается явное приведение значений индивидуального типа к базовому типу. Поясним это на примере.Пусть заданы следующие определения индивидуальных типов:
CREATE TYPE EMP_NO AS INTEGER FINAL;
CREATE TYPE DEPT_NO AS INTEGER FINAL;
CREATE TYPE PRO_NO AS INTEGER FINAL;
Тогда таблицу EMP можно определить следующим образом:
CREATE TABLE EMP (
EMP_ID EMP_NO,
EMP_NAME VARCHAR(20),
DEPT_ID DEPT_NO,
PRO_ID PRO_NO ) ;
Такое определение таблицы, приведет к тому, что хотя все три индивидуальных типа определены на одном и том же базовом типе INTEGER , попытка выполнить запрос
SELECT EMP_NAME
FROM EMP
WHERE EMP_ID > DEPT_ID ;
будет отвергнута системой (и это правильно, поскольку, скорее всего, запрос задан по ошибке). Но если действительно требуется сравнивать идентификаторы служащих с идентификаторами их отделов, то можно воспользоваться конструкцией явного приведения типа:
SELECT EMP_NAME
FROM EMP
WHERE CAST(EMP_ID TO INTEGER) > CAST(DEPT_ID TO INTEGER) ;
У читателей могут возникнуть законный вопрос: что означает ключевое слово FINAL в приведенных примерах определения индивидуальных типов?
Ответ может быть довольно неожиданным. С формальной точки зрения индивидуальный тип данных является частным случаем структурного типа данных. Обе разновидности UDT определяются единым синтаксисом. В частности, ключевое слово FINAL играет важную роль в определении структурного типа, указывая тот факт, что этот тип может быть использован только для создания объектов, а не для порождения новых типов на основе механизма наследования. При определении индивидуальных типов механизм наследования не используется и поэтому в определении любого индивидуального типа должно присутствовать ключевое слово FINAL .73 Далее, поскольку индивидуальный тип является частным типом структурного типа, для индивидуального типа можно определять методы.
В книгах Джима Мелтона [12-13] неоднократно подчеркивается семантическое сходство понятий индивидуального типа данных и домена в смысле SQL . Более того, утверждается, что в следующих версиях стандарта SQL использование доменов будет сначала объявлено нежелательным, а потом и вовсе будет запрещено. По мнению автора этой статьи, это сделать совсем непросто. Напомним, что в случае использования SQL -домена:
(a) в определении домена указывается базовый встроенный тип данных и, возможно, ограничение допустимых значений, которое распространяется на любой столбец, определенный на данном домене;
(b) для значений столбца, определенного на домене, допускаются все операции, допустимые для базового типа.
Естественно, эти возможности могут использоваться текущими пользователями стандарта SQL . В то же время, в случае использования индивидуального типа данных:
(a) в определении индивидуального типа указывается только базовый тип данных; если столбец определяется на индивидуальном типе данных, то для него обязательно придется специфицировать собственное ограничение целостности;
(b) для значений столбца, определенного на индивидуальном типе данных, не допускаются операции соответствующего базового типа (если не использовать операцию явного приведения типов).
Здесь явно имеются противоречия, для сглаживания которых требуется модифицировать понятие индивидуального типа данных.
Informix Universal Server (IUS)
Informix Universal Server (IUS ) представлял собой реализацию объектно-ориентированной технологии на основе встраивания механизма абстрактных типов данных и механизма наследования в популярный и надежный сервер реляционных баз данных Informix Dynamic Server .78Интеллектуальные большие объекты
Интеллектуальные большие объекты (smart large objects ), поддерживаемые в IUS , позволяют снять неприятные реализационные ограничения, характерные для трактовки больших объектов (BLOB или CLOB ) реляционными СУБД78. Такие объекты могут подвергаться журнализации и откату, что важно для сохранения целостности и доступности данных.В IUS -SQL операторы работают не с самими большими объектами, а с их описателями80. Эти описатели помещаются в столбцы таблиц, передаются подпрограммам, написанным с использованием встроенного SQL и т.д. Прикладная программа, получив описатель интеллектуального большого объекта, может работать с ним примерно так же, как и с файлом операционной системы. В частности, программисту, пишущему на ESQL /C (варианту языка C со встроенным SQL , поддерживаемому в Informix ), доступны следующие функции:
ifx_lo_read – чтение;
ifx_lo_readwithseek – чтение с предварительным позиционированием;
ifx_lo_write – запись;
ifx_lo_writewithseek – запись с предварительным позиционированием);
ifx_lo_seek – позиционирование и т.д.81
Использование ссылочных типов
В Oracle 8 строки объектных таблиц называются строчными объектами ( row objects ), а столбцы этих строк –столбцевыми объектами ( column objects ). Для всех строчных объектов обеспечивается возможность уникальной идентификации. Используется понятие объектного идентификатора, и столбец любой таблицы может быть определен на встроенном типе REF. Значения этого столбца являются своего рода указателями на строчные объекты той же самой или другой объектной таблицы. Считается, что REF - значение, указывающее на некоторый строчный объект, и сам этот строчный объект имеют разные, хотя и связные типы данных. Как утверждает Oracle , запросы с путевыми выражениями, основанными на наличии столбцов ссылочного типа, выполняются быстрее, чем эквивалентные запросы с соединениями.
Как появились ОРСУБД?
Два весьма известных специалиста в области технологии баз данных – Майкл Стоунбрейкер и Вон Ким – оспаривают пальму первенства в направлении ОРСУБД. Стоунбрейкер начал работать в области баз данных в начале 70-х гг. прошлого века в университете Беркли. Его первым всемирно известным проектом была СУБД Ingres , которая существует и используется до сих пор в двух ипостасях – как свободно распространяемая система (университетская Ingres ; код поддерживается в Беркли) и как коммерческая СУБД, принадлежащая компании Computer Associates . В исходном варианте СУБД Ingres отсутствовала поддержка языка SQL (поддерживался собственный язык запросов QUEL ), но система уже обладала некоторыми уникальными чертами, которые, с некоторой натяжкой, можно было бы назвать объектными (например, в СУБД Ingres допускалось определение пользовательских процедур, выполняемых на стороне сервера). Кроме того, в проекте Ingres очень большое внимание уделялось управлению правилами.В 80-е годы Майкл Стоунбрейкер возглавлял проект Postgres (вариант этой системы под названием PostgreSQL до сих пор является весьма популярным свободно доступным продуктов). В Postgres были реализованы многие интересные средства: поддерживалась темпоральная модель хранения и доступа к данным, и в связи с этим был абсолютно пересмотрен механизм журнализации изменений, откатов транзакций и восстановления БД после сбоев; обеспечивался мощный механизм ограничений целостности; поддерживались ненормализованные отношения (работа в этом направлении началась еще в среде Ingres), хотя и довольно странным способом: в поле отношения может храниться динамически выполняемый запрос к БД.
Одно свойство системы Postgres сближало ее со свойствами объектно-ориентированных СУБД. В Postgres допускалось хранение в полях отношений данных абстрактных, определяемых пользователями типов. Это обеспечивало возможность внедрения поведенческого аспекта в БД, т.е. решало ту же задачу, что и ООСУБД, хотя, конечно, семантические возможности модели данных Postgres были существенно слабее, чем у объектно-ориентированных моделей данных.
Основная разница состояла в том, что в Postgres не предполагалось наличие языка программирования, одинаково понимаемого как внешней системой программирования, так и системой управления базами данных. Как и в Ingres , в исходном варианте Postgres не поддерживался язык SQL (имелся собственный язык запросов Postquel ). Кстати, во времена Postgres Майкл Стоунбрейкер не использовал термин объектно-реляционная система, предпочитая называть свою СУБД системой следующего поколения.
В 90-е гг. Стоунбрейкер создал компанию Illustra , основной целью которой был выпуск коммерческого варианта СУБД Postgress , получившего название Illustra . В этой системе поддерживались основные идеи Postgres , но уже присутствовала и поддержка языка SQL . В конце 1995 г. компания Illustra была поглощена компанией Informix , и это привело к выпуску в 1996 г. СУБД Informix Universal Server .
Имя Вона Кима стало широко известно во второй половине 70-х гг., когда он примкнул к участию в экспериментальном проекте компании IBM System R . Наиболее известная ранняя работа доктора Кима была посвящена преобразованию SQL -запросов с целью превращения запросов с вложенными подзапросами в запросы с соединениями [29].
В 80-е гг. Вон Ким работал в компании MCC , где успешно выполнил реализацию серии прототипов ООСУБД Orion [30]. В этих прототипах были опробованы многие идеи объектно-ориентированных СУБД, которые обсуждались нами в разделе 2. Одной из интересных особенностей проекта было то, что в качестве основного языка программирования использовался объектный вариант известного функционального языка Lisp .
В конце 80-х д-р Ким основал компанию UniSQL , выпустившую в 1991 г. первую версию продукта UniSQL , которую Вон Ким стал называть объектно-реляционной системой. Трудно оценивать коммерческий успех этой СУБД. В настоящее время она принадлежит Корейской национальной телекоммуникационной компании и, по всей видимости, продолжает использоваться. Поскольку UniSQL была первой СУБД, официально называемой объектно-реляционной системой, приведем ее краткое описание.
UniSQL обеспечивает возможность построения так называемых федеративных систем баз данных. При этом предоставляется единое представление данных, которые могут храниться либо в базе данных, непосредственно управляемой UniSQL , либо в какой-либо из реляционных баз данных, управляемой СУБД Oracle , Informix , Sybase и т.д., либо в какой-либо дореляционной базе данных. Сервер UniSQL обеспечивает интегрированный доступ к данным, управляемым разными СУБД.
Разработчики UniSQL полагали, что построение полнофункциональной СУБД, основанной на принципиально новой модели данных, крайне проблематично. Был выбран подход к расширению реляционной модели, выражающийся в следующих четырех принципах:
В созданной компанией системе поддерживалось расширение стандарта SQL – SQL /X , одновременно включающее и объектно-ориентированные, и реляционные возможности. В частности, в отличие от подхода, принятого в стандарте ODMG , в одном языке поддерживались возможности и определения данных, и манипулирования ими. В качестве языковых средств программирования приложений поддерживались языки C ++ и Smalltalk .
После этого небольшого исторического очерка перейдем к рассмотрению особенностей трех ведущих СУБД, которые претендуют на поддержку объектно-реляционного подхода, – IBM Informix , Oracle и IBM DB 2. С точки зрения автора данной статьи, этот порядок изложения является справедливым, поскольку соответствует хронологии появления систем на рынке. При описании подходов к организации объектных расширений мы будем стремиться к изложению основных концепций, а не технических деталей. Кроме того, мы не будем стремиться к точному описанию современного состояния систем, поскольку, как отмечалось ранее, в настоящее время компании IBM и Oracle не слишком заинтересованы в развитии объектно-реляционных свойств своих систем, и в этом отношении современные продукты не слишком отличаются от вариантов пяти-шестилетней давности.
Конструируемые типы данных
Важность обеспечения конструируемых типов данных отмечалась и в Первом, и во Втором манифестах. В SQL :1999 обеспечиваются соответствующие (хотя и ограниченные) возможности.Манифест систем баз данных следующего поколения и его последствия
Через год после публикации Манифеста систем объектно-ориентированных баз данных вышел в свет Манифест систем баз данных следующего поколения [2], инициатором которого, очевидно, был Майкл Стоунбрейкер (хотя у документа формально много авторов). Мы говорим об этом достаточно определенно, поскольку в этом манифесте повсюду видны идеи Стоунбрейкера, использованные им в проектах Ingres и Postgres .В некотором роде Второй манифест стал ответом миру объектно-ориентированных баз данных со стороны мира SQL -ориентированных баз данных. Если обсуждавшийся в предыдущем разделе Первый манифест носил хотя и немного путанный, но все-таки научный характер, то Второй манифест является в большей степени инженерно-публицистическим документом. В некотором роде это реакция индустрии СУБД на неприятные для нее измышления из мира науки.
Второй манифест (или, вернее, работы, приведшие к его появлению) имел важные последствия. В 1995 г. компания Informix (ныне входящая в состав IBM ) купила компанию Майкла Стоунбрейкера Illustra 52, и Стоунбрейкер стал техническим директором Informix . В начале 1996 г. компания Informix объявила о выпуске принципиально нового продукта Informix Universal Server , в котором, как утверждала компания, сочетались лучшие черты Informix Online Server с развитыми объектными чертами, присущими Illustra .
К выпуску Informix Universal Server очень ревниво отнеслась компания Oracle , которая немедленно заявила, что у нее готов собственный объектно-реляционный продукт, по всем параметрам превосходящий систему компании Informix . Эта система, получившая название Oracle 8, была выпущена в конце лета 1996 г.
Годом позже группе производителей объектно-реляционных СУБД примкнула компания IBM , выпустившая продукт DB 2 Universal Database . (Как выяснилось позже – см., например, [11] – все наиболее важные свойства этого продукта были реализованы еще в 1995 г. в СУБД DB 2 for Common Servers . Просто компания IBM предпочла до поры не афишировать свои расширения.)
Первые пару лет вокруг объектно-реляционных СУБД стоял большой шум.
Позже выяснилось, что маркетинговые ожидания компаний-гигантов оказались преувеличенными. (В частности, это было одной из основных причин падения компании Informix .) Сегодня объектные расширения SQL -ориентированных СУБД предлагаются пользователям лишь в качестве дополнительных, хотя и важных возможностей.
Объектные расширения языка SQL были зафиксированы в стандарте SQL :1999. В той или иной мере эти расширения поддерживаются во всех трех перечисленных выше продуктах. В настоящее время ближе всех к стандарту находятся продукты компании Oracle .
В этом разделе мы сначала приведем изложение (с комментариями) Второго манифеста. Затем мы кратко обсудим основные идеи SQL :1999, относящиеся к объектным расширениям. Наконец, в третьем подразделе будут описаны наиболее интересные черты трех ведущих объектно-реляционных систем.
Наследование типов и таблиц
В IUS механизм наследования может применяться к типам записей и таблицам. Поддерживается только одиночное наследование. Все функции, определенные для супертипа, автоматически распространяются на все его подтипы. В то же время для подтипов могут определяться свои функции, как новые, дополняющие функциональность, так и модифицированные, изменяющие функциональность, унаследованную от предшественника. В последнем случае имеет место перекрытие функций. Значения подтипов могут использоваться почти везде, где разрешено употребление значений их супертипов. Единственное (и вполне естественное) ограничение возникает при отведении памяти и хранении значений. Здесь соответствие типов должно быть точным. Например, если предположить, что тип programmer является подтипом типа employee , и столбец таблицы имеет тип employee , то храниться в нем могут только значения данного типа, но не значения типа programmer .Наследование таблиц является развитием концепции наследования типов. В иерархии наследования могут участвовать только типизированные таблицы, типы которых (типы записи) образуют параллельную иерархию. Однако, кроме столбцов супертаблиц, подтаблицы наследуют ограничения целостности (первичные ключи, уникальность, ссылочные ограничения), опции хранения, триггеры, индексы и методы доступа.
Отношение наследования между таблицами является динамическим в том смысле, что, если меняются наследуемые характеристики супертаблиц, то это немедленно отражается и на подтаблицах (как на прямых наследниках, так и отделенных несколькими уровнями иерархии). По понятным причинам определения столбцов наследуемых таблиц изменять нельзя, но ограничения, индексы и триггеры – можно.
В IUS операции SELECT , UPDATE и DELETE , примененные к супертаблице, распространяются также и на все ее подтаблицы. Если требуется ограничить запрос ровно одной таблицей, следует употребить конструкцию ONLY . Идеология включения подтаблиц в супертаблицы распространяется и на построение представлений.
Объектная инфраструктура
Истинная объектно-реляционная система должна обеспечивать специальные средства для повышения эффективности приложений, связанных с большими объектами, и минимизации их влияния на системные ресурсы.В DB 2 поддерживаются три типа данных для хранения больших объектов: BLOB для бинарных объектов, CLOB для символьных строк и DBCLOB для строк, в которых используются двухбайтовые наборы символов. Когда большие объекты сохраняется в столбце таблицы, то на самом деле столбец содержит “дескриптор” каждого такого значения; сами же большие объекты хранятся вне таблицы.
Подсистема восстановления DB 2 дает возможность создателю таблицу выключать обычную журнализацию изменений столбцов с большими объектами. При выключенной журнализации по отношению к таким столбцам гарантируется согласованность транзакций, но столбец не может участвовать в процедуре прямого восстановления.
В среде DB 2 прикладная программа может объявить переменную-“локатор”, которая представляет значение большого объекта, но реально его не содержит. Локатор может быть использован для представления значения большого объекта в любом выражении SQL , и операции над локаторами очень эффективны, поскольку при их выполнении происходит работа с “предписаниями” по материализации, а не с сами значениями больших объектов. При использовании локаторов прикладная программа может выполнить серию действий над значением большого объекта, откладывая его материализацию до последнего момента.
DB 2 дает возможность прикладным программам обмениваться значениями больших объектов между базой данных и файлом без перемещения значений через буфера программы. В программе может быть объявлена переменная “ссылка на файл”, которая содержит имя нужного файла. Ссылка на файл может использоваться в операторах SQL как входная или выходная переменная, представляющая содержимое файла, которое интерпретируется как большой объект. Совместно локаторы и ссылки на файл часто дают возможность обработки больших объектов без их реального считывания в память программы.
Объектная модель SQL
Объектная модель SQL 69 не является тождественной объектным моделям какого-либо объектно-ориентированного языка программирования или какой-либо объектно-ориентрованной системы баз данных (включая модель ODMG – см. разд. 2). Однако при определении объектной модели SQL участники процесса стандартизации тщательно проанализировали ряд других языков и систем с целью выяснения достоинств и недостатков их объектных моделей70.По мнению авторов стандарта SQL :1999, выработанная ими объектная модель похожа на объектную модель языка Java , но при этом адаптирована к природе языка SQL как языка СУБД с наличием стабильно хранимых метаданных и данных 71.
Объектная модель SQL :1999 включает два основных отличительных компонента – структурные, определяемые пользователями типы данных (User Defined Type – UDT )и типизированные таблицы (Typed Table ). Первый компонент позволяет определять новые типы данных, которые могут быть гораздо более сложными, чем встроенные типы данных языка SQL . При определении структурного UDT требуется специфицировать не только содержащиеся в нем элементы данных, но и семантику типа данных, т.е. его поведение на основе интерфейса вызовов методов. Второй компонент – типизированные таблицы – позволяет определять таблицы, строки которых являются экземплярами (или значениями) UDT , с которым явно ассоциируется таблица.
В стандарте SQL :1999 определены два пакета объектных свойств – минимальный (PKG 006) и полный (PKG 007), которым должны удовлетворять SQL -ориентированные ОРСУБД, претендующие на соответствие стандарту. Ниже мы перечислим свойства, включенные в каждый из пакетов, но смысл этих свойств будет понятен только на основе последующих подразделов.
Пакет PKG 006 включает всего пять свойств:
свойство S 023 (“Basic structured types ”) – возможность определять UDT и их методы с ограниченными возможностями;
свойство S 041 (“Basic reference types ”) – возможность определять и использовать ссылки на экземпляры UDT , входящие в типизированные таблицы;
свойство S 051 (“Create table of type ”) – возможность создания типизированных таблиц;
свойство S 151 (“Type predicate ”) – возможность определения точного типа ( в иерархии типов) экземпляра UDT ;
свойство Т041 (“Basic LOB data type support ”)– возможность определения LOB -типов в смысле SQL (с необязательной поддержкой операций, кроме операций сохранения и полной выборки).
Пакет PKG 007 содержит девять дополнительных свойств:
свойство S 024 (“Enhanced structured types ”) – добавляет к свойству S 023 ряд развитых возможностей, в число которых входят возможности кодирования методов на языках, отличных от SQL , сравнения экземпляров UDT и передача экземпляров UDT в качестве параметров различных процедур;
свойство S 043 (“Enhanced reference types ”) – расширяет свойство S 041 возможностями определения ссылок с областью действия, автоматической проверки законности ссылок и т.д.;
свойство S071 (“SQL-paths in function and type name resolution”) – позволяет использовать путевые выражения SQL (SQL-path) в алгоритме разрешения типа;
свойство S 081 (“Subtables ”) – расширяет возможности свойства S 051, допуская организацию иерархии таблиц, аналогичной иерархии типов соответствующих UDT ;
свойство S 111 (“ONLY in query expressions ”) –обеспечивает возможность выборки только экземпляров указанного типа, без экземпляров любого из его подтипов;
свойство S 161 (“Subtype treatment ”) – дает возможность информировать среду SQL о том, что некоторый экземпляр UDT в действительности является экземпляром указанного подтипа;
свойство S 211 (“User -defined cast functions ”) – разрешает определять подпрограммы, преобразующие экземпляры UDT к другим типам;
свойство S 231 (“Structured type locators ”) – способствует доступу к экземплярам UDT из прикладных программ;
свойство S 023 (“Transform functions ”) – позволяет определять подпрограммы, преобразующие значения UDT в значения предопределенных типов данных и наоборот.
Объектно-реляционные СУБД
В этом разделе мы кратко обсудим, каким образом объектные расширения реализованы в трех ведущих РСУБД – Oracle , IBM Informix и DB 2. Заметим, что компания Microsoft решила не внедрять объектные расширения в свой основной продукт управления базами данных – Microsoft SQL Server . Аналогичное замечание относится и к основному продукту компании Sybase .Но в начале раздела мы приведем небольшой исторический очерк объектно-реляционного подхода к организации СУБД. Этот очерк носит очень субъективный характер и отражает исключительно личную точку зрения автора этой статьи.
Объектные представления
Объектные представления – это виртуальные таблицы, которые могут обладать структурой и поведением, отличным от структуры и поведения базовых таблиц, лежащих в основе этих представлений. Как и в случае типизированных таблиц, определение объектного представления основывается на определении структурного типа. Объектные представления можно использовать для ограничения доступа к подмножеству строк иерархии таблиц или для сокрытия некоторых столбцов этой иерархии.Если представление основывается только на выборке строк или таблиц, то определение представления может основываться на уже существующих определениях структурных типов. Однако, если в представлении требуется изменить набор столбцов или поведение базовых таблиц, то в качестве основы иерархии представлений необходимо определить новую иерархию типов.
В этом разделе мы кратко
В этом разделе мы кратко изложим существо объектных расширений, которые включены в стандарт SQL :1999. В этом изложении мы основываемся не на официальном тексте стандарта (он очень формален и скучен), а на книге Джима Мелтона [12], которая, по сути, является неформальным описанием семантики (rationale ) соответствующей части языка. В указанной книге объектным расширениям языка SQL посвящено более 200 страниц. Естественно, наше изложение будет несравненно более кратким (в частности, за счет отказа от приведения синтаксических правил).Объектные типы и объектные таблицы
Объектные типы в Oracle8 являются аналогом типа записи в IUS. Как и в IUS , для доступа к отдельным полям значений объектного типа используется “точечная” нотация.В Oracle 8 i при определении объектного типа можно, помимо спецификации структуры значений этого типа, определить и набор методов данного типа. Методы представляют собой функции или процедуры, написанные на PL/SQL, Java, C или другом языке89 и сохранённые в БД или вне её (при наличии регистрации в БД).
Любой метод объектного типа попадает в одну из трёх категорий:
Методы-члены вызываются в нотации
имя_объекта.имя_метода ( список_параметров )
имеют неявный параметр SELF и могут обращаться к значениям атрибутов объекта90.
Статические методы вызываются в нотации
имя_объектного_типа.имя_метода ( список_параметров )
и не могут обращаться к значениям атрибутов конкретных объектов.
Методы сравненияслужат для сравнения экземпляров объектов. Сравнение объектов может производиться с помощью методов вида MAP или вида ORDER. Метод типа MAP принимает в качестве параметра объект некоторого объектного типа, а возвращает значение одного из встроенных типов, которое может использоваться в операциях сравнения и сортировки. Таким образом, этот метод выполняет отображение объекта
на значение одного из встроенных типов.
Метод типа ORDER сравнивает два объекта и возвращает –1, если первый объект
меньше второго, 0, если объекты равны, и 1, если первый объект больше второго.
Если при определении объектного типа метод сравнения не задан, то объекты этого типа можно сравнивать только на равенство/неравенство, причём объекты не должны содержать элементов тип LOB. Тогда объекты считаются считаться равными, в том и только в том случае, когда все их элементы не содержат неопределенных значений, и значения соответствующих элементов совпадают.
Каждый объектный тип имеет определяемый системой метод-конструктор, который
создаёт новый объект этого типа и присваивает значения его атрибутам.
Метод-конструктор – это функция, которая возвращает объект данного типа. Имя метода-конструктора совпадает с именем объектного типа, имена и типы параметров
конструктора – с именами и типами атрибутов объектного типа.
Объектной таблицей в Oracle 8 называется таблица, строки которой имеют объектный тип. В Oracle 8 не поддерживалось наследование (ни типов, ни таблиц), но уже в Oracle 8 i появилась возможность наследования таблиц почти в той же форме, как это делалось в IUS , но без поддержки параллельной иерархии наследования объектных типов 91.
К объектным представлениям можно обращаться так же, как и к объектным таблицам (по крайней мере, по выборке данных). Можно определять объектные представления на основе других представлений (возможно, объектных).
Определение новых базовых типов данных
IUS позволяет вводить новые базовые типы данных. При этом можно использовать как встроенные в IUS методы доступа и хранения, так и определять новые. Для начала рассмотрим способ создания новых базовых типов с использованием встроенных механизмов хранения.Необходимость в создании новых базовых типов может возникать во многих случаях. Одним из самых простых случаев - это использование разных метрических систем для одного и того же понятия. Например, если некоторая фирма закупает детали в Америке, то их размеры будут указаны в футах, а цена в долларах. Если аналогичные детали закупаются в Германии, то их размеры указываются в метрической системе, а цена в евро.
IUS позволяет построить новый базовый тип данных, основанный на существующем типе, но обеспечивающий автоматическое преобразование к нужному значению. Сами типы вводятся следующими операторами:
CREATE DISTINCT TYPE usd AS MONEY;
CREATE DISTINCT TYPE euro AS MONEY;
Далее требуется ввести функции преобразования значений из долларов в евро и наоборот, а также описать возможность такого преобразования:
CREATE FUNCTION usd_to_euro (v usd) RETURNS euro; . . .
CREATE FUNCTION euro_to_usd (v euro) RETURNS usd; . . .
CREATE IMPLICIT CAST (usd AS euro WITH usd_to_euro);
CREATE IMPLICIT CAST (euro AS usd WITH euro_to_usd);
После этого можно сравнивать значения типов usd и euro , полученные из разных таблиц, не вызывая явно функцию преобразования. Такое решение существенно снижает возможность внесения ошибок, связанных с преобразованием значений.82
Другой причиной, по которой может возникнуть необходимость во введении нового базового типа данных – это принципиальное отсутствие такого типа. Для этого поддерживается механизм определения типов со скрытой структурой (Opague Types ). Типы со скрытой структурой являются абстрактными в строгом смысле этого слова. IUS лишен какой-либо информации о внутреннем устройстве этих типов и может манипулировать соответствующими значениями только посредством предоставленных разработчиком функций.
Чтобы определить тип со скрытой структурой, необходимо выполнить следующую последовательность действий:
описать на языке C (или другом внешнем языке) структуру определяемых объектов;
написать на языке C (или другом внешнем языке) вспомогательные функции, вызываемые сервером СУБД;
зарегистрировать определяемый тип в базе данных посредством оператора CREATE OPAQUE TYPE;
зарегистрировать вспомогательные функции посредством операторов CREATE FUNCTION и CREATE CAST;
предоставить права доступа к определяемому типу и его вспомогательным функциям посредством оператора GRANT;
написать требующиеся для приложения дополнительные функции, которые можно вызывать средствами SQL, и зарегистрировать их;
если нужно, реализовать специфические для определяемого типа вторичные методы доступа (функции для работы с индексами).
Определение структурных типов
Имя определяемого пользователем типа данных имеет, в общем случае, традиционную для SQL трехзвенную архитектуру – имя_каталога.имя_схемы.имя_типа . Определение структурного UDT может содержать раздел подтипизации. Если этот раздел присутствует в определении UDT , то в нем указывается имя ранее определенного UDT , атрибуты и методы которого будут наследоваться определяемым структурным типом.Структурные типы, определяемые без использования наследования, называются максимальными супертипами (поскольку у любого из таких типов супертип отсутствует).74 В определениях максимального структурного супертипа или индивидуального типа обязан присутствовать раздел представления. В этом разделе представления может указываться имя предопределенного встроенного типа, и это означает, что определяется индивидуальный тип. Указание списка определений атрибутов соответствует определению структурного типа.
Заметим, что раздел представления может отсутствовать. В этом случае должен присутствовать раздел подтипизации, и представление заново определяемого структурного типа полностью наследуется из определения структурного UDT , имя которого указано в разделе подтипизации.
Имя определяемого атрибута должно отличаться от имен всех других атрибутов определяемого типа, включая имена атрибутов, наследуемых от супертипа, и имена атрибутов типа данных определяемого атрибута. Тип данных может быть любым допустимым в SQL типом данных (включая конструируемые типы ARRAY и ROW и UDT ), кроме определяемого структурного типа и его супертипов.
Для атрибута можно объявить значение по умолчанию. Если типом данных атрибута является встроенный тип данных, то значение атрибута объявляется в том же синтаксисе, что и значение столбца по умолчанию в определении таблицы. Если типом данных атрибута является UDT (индивидуальный или структурный), тип ROW или ссылочный тип (см. следующий подраздел), то единственным допустимым значением по умолчанию является неопределенное значение (NULL ). Если же типом данных атрибута является тип ARRAY , то значением по умолчанию может быть NULL или пустое значение-массив (указывается как ARRAY [] ).
Для каждого определения атрибута, в котором типом атрибута является структурный тип, система автоматически генерирует пару методов, имена которых совпадают с именем атрибута. Первый метод является наблюдателем (observer ). Он вызывается без явных параметров и выдает значение указанного атрибута в значении того структурного типа, к которому применяется. Второй метод является мутатором (mutator ). Он вызывается с одним явным параметром – значением типа аргумента, применяется к некоторому местоположению (столбцу, переменной или параметру), где находится значение определяемого структурного типа, и этот вызов приводит к тому, что значение заменяется новым значением того же типа с измененным соответствующим образом значением данного аргумента.
Присутствие в определении атрибута раздела проверки области действия ссылочных значенийвозможно (и требуется) в том и только в том случае, когда типом определяемого атрибута является ссылочный тип. Более подробно мы обсудим суть этой спецификации в следующем подразделе. Пока лишь кратко заметим, что этот раздел указывает системе, должна ли она проверять, что каждое значение этого атрибута является ссылкой на существующий экземпляр указанного структурного типа, и должна ли система вызывать ссылочное действие при удалении экземпляра, на который ведет ссылка.75
Можно определить инстанциируемый (instantiable ) или неинстанциируемый (not instantiable ) структурный тип. Для неистанциируемого типа не определяется конструктор, и поэтому невозможно создать значение этого типа.76 Поэтому такие типы применимы только для определения инстанциируемых подтипов. Назначение неинстанциируемых типов состоит в моделировании абстрактных концепций, на которых основываются более конкретные концепции. Неинстанциируемые типы могут быть типами атрибутов других структурных типов, типами столбцов, переменных и т.д. Однако в соответствующих местоположениях всегда должно находиться либо значение инстанциируемого подтипа данного неинстанциируемого типа, либо неопределенное значение.
Обязательный раздел окончательности определения указывает на возможность или невозможность определения подтипов определяемого структурного типа. При определении индивидуального типа всегда требуется указывать FINAL . При определении структурного типа в SQL :1999 требуется указание NOT FINAL . Это требование не обосновано, и в следующих версиях стандарта SQL будет разрешено определять структурные типы, от которых невозможно наследование.
Хотя типизированные таблицы обсуждаются в следующем подразделе, мы вынуждены немного забежать вперед, чтобы ввести синтаксис и пояснить смысл раздела спецификации ссылочного типаопределения структурного типа. Строки типизированных таблиц обладают всеми характеристиками объектов в объектно-ориентированных системах, включая уникальные идентификаторы, которые могут использоваться для ссылок из других компонентов среды. В SQL :1999 поддерживаются три различных механизма присваивания уникальных идентификаторов экземплярам структурных типов, ассоциированных с такими таблицами (для всех строк таблицы, ассоциированной с данным структурным типом, используется один и тот же механизм). Уникальные идентификаторы экземпляров структурного типа могут представлять собой следующее:
значения, генерируемые системой автоматически;
значения некоторого встроенного типа SQL , которые должны генерироваться приложением при сохранении экземпляра структурного типа как строки типизированной таблицы;
значения, порождаемые из одного или нескольких атрибутов структурного типа.
Если в определении структурного типа присутствует раздел спецификации ссылочного типа, и указывается, что ссылочные значения будут генерироваться пользователями, то в определении структурного типа может присутствовать и раздел преобразования значений встроенного типа в значения ссылочного типа и наоборот.
Раздел преобразования типов может присутствовать только в определении индивидуального типа. Спецификации раздела обеспечивают возможности преобразования значений индивидуального типа в значения базового встроенного типа и наоборот.
В определении структурного типа может присутствовать раздел объявления сигнатур методов, ассоциируемых с определяемым структурным типом. Имеется возможность определять первичные методы, которые не применимы к любому супертипу определяемого структурного типа. Если определяемый тип является подтипом некоторого другого типа, то можно также определить подменяющие методы. Подменяющий метод имеет то же имя и тот же список аргументов, что и метод, определенный в некотором супертипе определяемого типа.
Исходный метод может быть определен как метод экземпляра, статический метод или метод-конструктор. Методы экземпляра действуют над экземплярами определяемого типа. Статические методы не используют экземпляры типа и не влияют на них; такие методы действуют над самим типом. Наконец, методы-конструкторы используются для инициализации экземпляров типа. Поскольку у неинстанциируемого типа не может быть экземпляров, для него могут быть определены только статические методы. Если при определении первичного метода не указывается его разновидность, этот метод считается методом экземпляра.
В сигнатуре метода указывается имя, по которому этот метод будет вызываться (вызывное имя – invocable name ). Кроме того, можно указать точное имя метода (specific name ), которое может быть использовано для уникальной идентификации метода, если его вызывное имя перегружено. Если у метода имеются какие-либо параметры, отличные от неявного параметра SELF , то в определении должен присутствовать заключенный в скобки список пар <имя_параметра, тип_параметра>, разделяемых запятыми. Поскольку методы являются функциями, требуется указать тип возвращаемого значения. Методы могут возвращать значения любого допустимого в SQL типа, даже структурного типа, ассоциированного с методом.
Наконец, у каждого метода имеется набор характеристик метода. Методы могут быть написаны на языке SQL или на любом из языков программирования, поддержка которых предусмотрена в стандарте SQL (Ada , C , COBOL , Fortran , MUMPS 77, Pascal , PL /1).
Язык Java поддерживается в стандарте несколько в иной манере, чем другие языки. Список параметров метода может быть определен в стиле, более соответствующем стилю SQL -подпрограмм (каждый параметр может принимать неопределенное значение, и не требуется параметр кода возврата). Для этого в качестве характеристики метода нужно указать PARAMETER STYLE SQL . Можно определить список параметров в стиле, более близком стилю различных языков программирования (параметру, который может принимать неопределенное значение, должен быть придан дополнительный параметр-индикатор, и должен быть явно определен выходной параметр кода ответа). В этом случае метод должен иметь характеристику PARAMETER STYLE GENERAL . Наконец, для методов, тела которых будут писаться на языке Java , нужно указать характеристику PARAMETER STYLE JAVA .
Любой метод может быть детерминированным или недетерминированным. Детерминированный метод всегда возвращает один и тот же результат, если вызывается с одним и тем же набором аргументов при одном и том же состоянии базы данных. По умолчанию методы считаются недетерминированными.
У каждого метода имеется характеристика, указывающая связь этого метода с SQL . Можно указать следующие варианты:
метод не содержит операторов SQL (NO SQL );
метод содержит операторы SQL , но не обращается к базе данных (CONTAINS SQL );
метод может производить выборку из базы данных, но не обновляет базу данных (READS SQL DATA );
в методе допускаются обновления базы данных (MODIFIES SQL DATA ).
По умолчанию принимается характеристика CONTAINS SQL . Наконец, для каждого метода можно определить его реакцию на аргументы, являющиеся неопределенными значениями. Если указывается RETURN NULL ON NULL INPUT , то метод всегда возвращает неопределенное значение, если значение любого из его аргументов является неопределенным. Если же указывается CALLED ON NULL INPUT (или если характеристика явно не задана), то метод всегда явно выполняется при вызове с любым набором аргументов.
Определение типизированной таблицы
С точки зрения синтаксиса оператор определения типизированной таблицы является частным случаем оператора создания базовой таблицы CREATE TABLE . Первой существенной особенностью оператора создания типизированной таблицы является обязательное наличие раздела OF , в котором указывается имя ранее определенного структурного типа. Строки типизированной таблицы являются экземплярами ассоциированного с таблицей структурного типа.Далее, при определении типизированной таблицы можно объявить ее подтаблицей некоторой другой типизированной таблицы (имя супертаблицы указывается в разделе UNDER ). Супертаблица должна быть ассоциирована со структурным типом, являющимся непосредственным супертипом определяемой подтаблицы. Каждый столбец указанной супертаблицы наследуется подтаблицей; наследуются и характеристики столбцов супертаблицы – значения по умолчанию, ограничения целостности и т.д. Эти столбцы называются унаследованными столбцами подтаблицы, и они соответствуют атрибутам UDT подтаблицы, унаследованным от UDT супертаблицы. Кроме того, подтаблица будет содержать по одному столбцу для каждого собственного атрибута ассоциированного структурного типа. Такие столбцы подтаблицы называются заново определенными.
Как это принято в SQL , столбцы типизированной таблицы имеют порядковые номера. При этом унаследованные столбцы нумеруются до заново определенных и имеют те же номера, которые имели столбцы супертаблицы.
В определении типизированной таблицы разрешается указывать табличные ограничения целостности. Если определяемая таблица является подтаблицей некоторой супертаблицы, то в ней не допускается определение ограничения первичного ключа (PRIMARY KEY ). Однако, если определяется максимальная супертаблица, то в ее определении допускается спецификация PRIMARY KEY (с указанием одного или нескольких столбцов) или спецификация ограничения UNIQUE (с указанием одного или нескольких столбцов) в комбинации с указанием NOT NULL . В определении типизированной таблицы могут также содержаться спецификации ссылочных ограничений целостности.
Ссылки ( по значению) могут вести как на типизированную, так и на обычную таблицу.
В определении максимальной супертаблицы должна присутствовать спецификация “самоссылающегося” (self -referencing ) столбца, и самоссылающийся столбец, определенный в максимальной супертаблице, наследуется любой ее подтаблицей. Эта спецификация не может входить в определение подтаблицы. Семантика самоссылающихся столбцов обсуждается в этом подразделе ниже.
Наконец, для столбцов определяемой типизированной таблицы можно указывать опции столбцов. Опции столбца можно указывать только для заново определенных столбцов, для унаследованных столбцов это не допускается. Раздел области действия ссылок может входить в опции только заново определяемого столбца с типом REF (детали см. ниже). Для заново определяемого столбца некоторого типа символьных строк можно указать желаемый порядок на соответствующем наборе символов. Имеется опция для указания значения столбца по умолчанию, отличного от значения по умолчания соответствующего атрибута ассоциированного с определяемой таблицей структурного типа. Наконец, для заново определяемого столбца можно указать одно или несколько ограничений, включая проверочные ограничения.
Определяемые пользователями функции
В DB 2 имеется возможность создания определяемых пользователями функций (User -Defined Functions - UDF ) с использованием языков C , C ++ и Basic . UDF могут принимать параметры и могут быть использованы в любом выражении SQL , где предполагается наличие скалярного значения.Поддерживается соглашение о передаче параметров UDF в поставляемую пользователем программу реализации функции. Создатель функции должен откомпилировать реализующую ее программу и поместить выполняемый файл в каталог, доступный серверу баз данных. После этого пользователь должен зарегистрировать UDF в каждой базе данных, где предполагается ее использование, путем выполнения оператора CREATE FUNCTION . Описание функции помещается в таблицы системного каталога. При каждом вызове функции ее реализация будет динамически загружаться и выполняться. DB 2 SQL позволяет “перегружать” имя функции, т.е. определять несколько функций с одним именем и разными типами параметров. При обработке вызова функции DB 2 вызывает функцию, сигнатура которой строго соответствуют типам аргументов вызова.
Определяемые пользователями типы
Думаю, что не стоит снова обосновывать потребность в UDT . Об этом много говорилось ранее в этой статье. Поэтому сразу перейдем к сути предложений SQL :1999. Как отмечалось выше, в стандарте поддерживается возможность определения пользователями двух разновидностей UDT – структурных типов (structured type ) и индивидуальных типов (distinct types ).В DB 2 определяемые пользователями типы данных называются “индивидуальными типами” (“distinct type ”). В каждом из индивидуальных типов используется общее представление одного из встроенных типов (называемых “базовыми типами”), но может иметься собственный набор допустимых операций. Легко указать, какие из операций базового типа являются осмысленными для созданного на его основе индивидуального типа. Каждый встроенный оператор, такой как “+ ”, реализуется функций с тем же именем, что и оператор. Чтобы сделать этот оператор применимым к индивидуальному типу, нужно просто создать функцию с тем же именем, что и оператор, принимающую параметры и/или возвращающую результат индивидуального типа данных. Функция, реализующая оператор, может основываться на функции, реализующей встроенный оператор.
По мнению автора этой статьи,
По мнению автора этой статьи, после выпуска в 1997 г. системы Oracle 8 88, которая действительно претендовала на статус объектно-реляционной системы, впоследствии корпорация Oracle не стала уделять большого внимания развитию именно этих свойств своей системы. Лишь в системе Oracle 9 i (2002 г.) появились существенные дополнения. Поэтому в своем кратком описании мы в основном ограничимся свойствами Oracle 8, но в заключение подраздела обозначим и возможности, появившиеся в Oracle 9 i .Предложения, касающиеся управления объектами и правилами
Создатели СУБД не в состоянии предвидеть все виды элементов данных, которые могут потребоваться приложениям. СУБД третьего поколения должны управлять разнообразными объектами, и авторы манифеста выдвигают четыре предложения, относящиеся к управлению объектами, конструкторам типов, наследованию, функциям и уникальным идентификаторам.Предложение 1.1: Система типов СУБД третьего поколения должна быть богатой и разнообразной.
Все перечисленные механизмы являются желательными:
1) система абстрактных типов данных для создания новых базовых типов;
2) конструктор типа массив;
3) конструктор типа последовательность;
4) конструктор типа запись;
5) конструктор типа множество;58
6) функции как тип;
7) конструктор типа объединение;
8) рекурсивная композиция всех перечисленных выше конструкторов.
Первый механизм позволяет конструировать новые базовые типы в дополнение к стандартному набору типов, имеющемуся в большей части систем. Должно быть возможно определять типы битовых строк, точек, линий, комплексных чисел и т.д. Второй механизм позволяет использовать массивы элементов данных. Обычным свойством массивов является отсутствие возможности вставить новый элемент в середину, сдвинув все последующие элементы. В некоторых приложениях такая вставка бывает необходимой, и конструктор третьего вида поддерживает подобные последовательности. Четвертый механизм позволяет группировать элементы данных в записи. Пятый механизм требуется для создания неупорядоченных наборов элементов данных или записей. Шестой механизм – функции (методы) – обсуждается в предложении 1.3; желательно, чтобы СУБД поддерживала такие конструкции. Следующий механизм позволяет создавать элементы данных, которые могут принимать значения одного из нескольких типов.59
Последний механизм позволяет рекурсивно комбинировать конструкторы типов для поддержки сложных объектов, обладающих внутренней структурой.
Более того, в отличие от систем второго поколения, последний примененный конструктор типов не обязан быть конструктором множеств.60
Возможно, со временем станут желательными и дополнительные конструкторы типов. Например, системы обработки транзакций управляют очередями сообщений. Поэтому может возникнуть необходимость в конструкторе, создающем очереди.
Системы второго поколения обладают лишь частью перечисленных конструкторов типов, и сторонники объектно-ориентированных баз данных утверждали, что для поддержки всех этих возможностей должны появиться качественно новые СУБД. Авторы манифеста придерживались другой точки зрения. В манифесте утверждается, что все обсуждаемые конструкторы типов можно добавить к реляционным системам как естественное расширение, и что технология этого расширения достаточно хорошо продумана. Более того, уже в то время начали появляться коммерческие реляционные системы с некоторыми из перечисленных возможностей.
Предложение 1.2: Наследование – хорошая идея.
Возможность организации типов в иерархию наследования является хорошей идеей. Более того, авторы манифеста считали, что существенно множественное наследование, так что иерархия наследования должна представляться ориентированным графом. Поддержка только единичного наследования оказывается недостаточной для адекватного моделирования подавляющего большинства ситуаций. Отмечается, что, хотя в Первом манифесте и защищается идея наследования, множественное наследование там приводится как необязательная возможность.
Желательно также иметь наборы, для которых не задаются дополнительные поля. Например, набор TEENAGER (подросток) можно было бы определить как набор, состоящий из таких же элементов данных, что и PERSON , но обладающий ограничениями на возраст. Опять-таки, уже создавались прототипы, демонстрирующие, как добавлять эти возможности к реляционным системам, и авторы манифеста ожидали, что коммерческие реляционные системы будут развиваться в этом направлении.61
Предложение 1.3: Функции, в том числе процедуры и методы баз данных, и инкапсуляция – хорошие идеи.
В системах второго поколения имеется лишь ограниченная поддержка функций и инкапсуляции. Например, в SQL над таблицами возможны только операции, осуществляемые функциями create , alter и drop .62 Абстракция таблицы доступна только путем выполнения одной из перечисленных функций.
Очевидно, что выгоды, предоставляемые инкапсуляцией, должны стать доступными для разработчиков приложений, чтобы те могли ассоциировать функции с пользовательскими наборами данных. Например, должна иметься возможность ассоциировать функции HIRE ( EMPLOYEE ) , FIRE ( EMPLOYEE ) и RAISE - SAL ( EMPLOYEE ) (нанять, уволить служащего и повысить ему зарплату) с уже знакомым набором данных EMPLOYEE . Если пользователям не разрешен прямой доступ к набору EMPLOYEE , а вместо этого предоставлены упомянутые функции, то вся информация о внутренней структуре объектов класса EMPLOYEE инкапсулируется внутри этих функций.63
Использование инкапсуляции дает административные преимущества путем поощрения модульности и регистрации функций вместе с инкапсулируемыми данными. Если набор EMPLOYEE изменяется так, что его предыдущее содержимое нельзя определить как представление, весь код, который необходимо изменить, локализован в одном месте, следовательно, его проще модифицировать.
В защищенных или распределенных системах применение инкапсуляции часто дает выигрыш в производительности. Например, функции HIRE ( EMPLOYEE ) в процессе выполнения несколько раз может потребоваться доступ к базе данных. Если HIRE ( EMPLOYEE ) задана как функция, которая должна быть выполнена сервером базы данных внутренним образом, то между приложением и СУБД состоится только один цикл обмена сообщениями. С другой стороны, если функция запускается из программы пользователя, один цикл обмена сообщениями потребуется для каждого доступа. 64
Наконец, такие функции могут быть унаследованы и, возможно, переопределены в иерархии наследования. Другими словами, функция HIRE ( EMPLOYEE ) может быть автоматически применена к набору STUDENT - EMPLOYEE .
Если воспользоваться возможностью переопределения, функцию HIRE для набора STUDENT - EMPLOYEE можно переписать. Словом, использование инкапсулированных функций крайне желательно. Однако авторы манифеста приводят три замечания.
Во-первых, пользователям следует писать функции на языке программирования высокого уровня и получать доступ к базам данных при помощи непроцедурного языка доступа высокого уровня. Язык доступа может быть встроен в язык программирования средствами препроцессора или реализован как прямое расширение языка программирования. Прямой доступ к внутренностям системы должен стать допустимым, но крайне нежелательным способом написания функций.65
Второе замечание касается понятия непрозрачных типов. Некоторые энтузиасты идеи объектно-ориентированных баз данных утверждают, что должен быть только один способ, с помощью которого пользователь может получить доступ к набору – выполнение одной из функций, применимых к набору. Такое ограничение игнорирует потребности языка запросов, среде выполнения которого требуется непосредственный доступ к каждому элементу данных. Необходим механизм, делающий типы прозрачными, чтобы к элементам данных этих типов можно было получить доступ через язык запросов.
Последнее замечание касается коммерческого рынка. Все крупнейшие поставщики СУБД второго поколения уже поддерживают функции, написанные на языке программирования высокого уровня (обычно на поддерживаемом поставщиком 4GL ), которые могут производить обращения к СУБД в терминах SQL . Более того, эти функции могут быть использованы для инкапсуляции доступа к данным, которыми они управляют. Поставщикам коммерческих реляционных систем осталось поработать над поддержкой наследования функций.
Предложение 1.4: Уникальные идентификаторы (UID ) записей должны задаваться СУБД только в том случае, когда недоступен определенный пользователем первичный ключ.
В системах второго поколения поддерживается понятие первичного ключа – заданного пользователем уникального идентификатора.
Неизменный первичный ключ лучше присвоенного системой UID , потому что обозначает нечто естественное, понятное человеку. При обмене данными или отладке это может быть значительным преимуществом. Если для набора первичный ключ недоступен, появляется необходимость в присвоенном системой уникальном идентификаторе. Некоторые наборы данных не обязательно обладают системно заданными UID , так что построение систем с принудительной уникальной идентификацией, вероятнее всего, окажется нежелательным.
Предложение 1.5: Правила (триггеры, ограничения) станут одной из ключевых характеристик будущих систем.
Правила не следует ассоциировать с определенными функциями или наборами. Исследователи объектно-ориентированных баз данных обычно игнорировали необходимость правил. На вопрос о правилах энтузиасты ООБД отвечали либо молчанием, либо предложением внедрять их путем включения кода для их поддержки в одну или несколько функций, работающих с набором.
С точки зрения авторов манифеста, имеется только одно разумное решение: правила должны поддерживаться СУБД, но не быть привязаны ни к какой функции и ни к какому набору. Из этого положения следуют два факта. Во-первых, парадигма ООБД “все выражается методами” просто не применима к правилам. Во-вторых, нельзя предоставлять непосредственный доступ к внутренним интерфейсам СУБД ниже уровня активации правил (иначе пользователи смогут обходить систему, включающую правила в нужное время).
Ко времени написания Второго манифеста уже существовали продукты поставщиков систем второго поколения, отвечающие приведенному предложению. Тем самым, в вопросах, касающихся этого предложения, коммерческий реляционный рынок опередил уровень исследований ООБД.
Предложения, касающиеся увеличения функциональных возможностей СУБД
Как уже отмечалось, системы третьего поколения не должны делать шаг назад, то есть они должны вобрать в себя все возможности, предоставляемые системами второго поколения. Особого внимания заслуживают язык запросов, спецификация множеств элементов данных и независимость данных. Следующие четыре предложения, касаются перечисленных вопросов.Предложение 2.1: Все виды программируемого доступа к базам данных должны осуществляться через непроцедурный язык доступа высокого уровня.
В литературе, посвященной ООБД, как правило, недооценивается критическая важность высокоуровневых языков доступа к данным, по выразительной силе не уступающих реляционному языку запросов. Например, в Первом манифесте
выдвигается предложение, что СУБД должна предоставлять возможность интерактивного доступа к данным в любой удобной форме. Авторы Второго манифеста делают более сильное утверждение: выразительная сила языка запросов должна присутствовать в любом интерфейсе программируемого доступа; не должно быть других способов доступа к данным СУБД. В перспективе такой сервис может быть обеспечен путем добавления конструкций языка запросов к различным языкам программирования со стабильным хранением данных. В ближайшем будущем этот сервис может быть обеспечен путем встраивания языка запросов в обычные языки программирования.
Многие исследователи OODB утверждают, что для приложений, ради которых они разрабатывают свои системы, желательна навигация к искомым данным с использованием низкоуровневого процедурного интерфейса. В частности, им требуется интерфейс с СУБД, с помощью которого можно получать доступ к определенным записям. Один или более элементов данных записи будет иметь тип “ссылка на запись в каком-то другом наборе”, обычно представляемым своего рода указателем на запись другого набора, то есть идентификатором объекта. Далее, приложение выберет один из указателей для создания новой текущей записи. Этот процесс будет продолжаться до тех пор, пока приложение не доберется до искомых данных.
По мнению авторов Второго манифеста, подобные интерфейсы неудобны, и использовать их не следует. Во-первых, когда программист осуществляет навигацию к искомым данным, он заменяет функции оптимизатора запросов написанными вручную вызовами более низкого уровня. История наглядно продемонстрировала, что хорошо написанный и хорошо настроенный оптимизатор почти во всех случаях добивается лучших результатов, чем написанные вручную вызовы. Далее, если изменится некоторое число индексов или данные в кластере будут реорганизованы, навигационный интерфейс не сможет автоматически приспособиться к переменам. Значит, если изменятся физические пути доступа к данным, программисту придется модифицировать программу. С другой стороны, оптимизатор запросов просто создает новый план, который оптимизируется для новой среды.
Авторы Второго манифеста утверждают, что их подход приносит выигрыш в производительности по сравнению с использованием низкоуровневых интерфейсов. Это утверждение, на первый взгляд, противоречит интуиции и нуждается в объяснениях. Подавляющее большинство энтузиастов ООБД считает, что указатель должен быть мягким, т.е. его значение не должно меняться, даже если элемент данных, на который он указывал, был передвинут. Эта характеристика, называемая позиционной независимостью, является желательной, так как она позволяет перемещать элементы данных, не меняя при этом структуры базы данных. Перемещения элементов данных часто неизбежны при реорганизации базы данных или восстановлении после сбоев. Таким образом, энтузиасты ООБД рекомендуют использовать в качестве указателей позиционно независимые уникальные идентификаторы. В этом случае для перехода по указателю необходим доступ к хэшированной или индексированной структуре уникальных идентификаторов.
В SQL -представлении, пара (имя-отношения, ключ) в точности является позиционно независимым уникальным идентификатором, задающим тот же хэшированный или индексированный просмотр. Все накладные расходы, связанные с синтаксисом SQL , с высокой степенью вероятности придутся на время компиляции.
Поэтому авторы Второго манифеста утверждают, что использование интерфейсов низкого уровня для возвращения единственного элемента данных дает в лучшем случае лишь микроскопический выигрыш в производительности. Если же возвращается несколько элементов данных, то замещение запроса высокого уровня множеством вызовов низкого уровня может снизить производительность из-за расходов на организацию вызовов от приложения к СУБД.
Наконец, энтузиасты ООБД часто утверждают, что программисты, например, САПР, хотят собственноручно осуществлять навигацию, и поэтому система должна поощрять ее при помощи интерфейсов низкого уровня. Да, некоторые программисты могут предпочитать навигацию. Были такие, которые отказывались переходить с языка ассемблера на языки высокого уровня, были и те, кто отказывался переходить к реляционным системам – на новых системах задачи были не столь сложными, а, значит, работа не столь интересная. Эти программисты думали, что смогут работать лучше, чем компиляторы и оптимизаторы. Авторы манифеста считают, что аргументы против навигации достаточно убедительны и что некоторым программистам просто не мешает подучиться.
Предложение 2.2: Должно быть по крайней мере два способа спецификации наборов: посредством перечисления членов и путем использования языка запросов для задания членов.
В литературе по ООБД предлагается задание множеств перечислением, средствами связанного списка или массива идентификаторов членов. Авторы манифеста полагают, что такая спецификация не является лучшим выбором.
Имеются, по меньшей мере, два способа задания наборов, таких как множества, массивы, последовательности и т.д. Их можно определять “экстенсионально” при помощи набора указателей или “интенсионально” при помощи выражения. Интенсиональная спецификация поддерживает автоматическое определение принадлежности к множеству, что желательно для большинства приложений. Экстенсиональная спецификация предпочтительна лишь в тех случаях, когда между членами множества отсутствует структурная связь или когда автоматическое определение членства нежелательно.
При интенсиональной спецификации оптимизатор запросов может производить семантические преобразования. Это позволяет выбирать пути доступа, лучшие для данного запроса. Никаких ограничений, налагаемых структурами указателей, не существует. Таким образом, полномочия по принятию решений по вопросам физического представления делегируются администратору базы данных. Администратор может решать, какие способы доступа следует поддерживать (например, связанные списки или массивы указателей).
Оба представления необходимы, но предпочтение должно отдаваться интенсиональному. С другой стороны, энтузиасты ООБД, как правило, рекомендуют использовать лишь экстенсиональные методы. В середине 70-х годов преимуществам автоматического задания множеств посвящалось немало внимания. Чтобы не сделать шаг назад, системы третьего поколения должны отдавать предпочтение автоматическим множествам.
Предложение 2.3: Существенно наличие обновляемых представлений.
Существует очень немного статических баз данных – большая часть данных постоянно изменяется. При изменениях наборов данных может потребоваться модификация программ. Очевидно, что инкапсуляция доступа к базе данных в функции и инкапсуляция функций в один набор была бы полезным шагом. Это позволило бы легко выявлять функции, в которые необходимо внести изменения. Однако это решение не является достаточным. Если изменяется схема базы данных, то на переписывание затронутых этими изменениями функций могут уйти недели или даже месяцы. В это время база данных не может просто перестать работать.
Гораздо лучшим подходом является поддержка виртуальных наборов (представлений). В системах второго поколения поддерживались некоторые возможности в данной области, что было продвижением вперед по сравнению с системами первого поколения. К сожалению, обновление реляционных представлений часто оказывается невозможным. Системы третьего поколения должны демонстрировать лучшее поведение при обновлении представлений.
Традиционным способом поддержки обновления представлений заключается в том, что для каждого набора элементов данных, над которым может быть построено обновляемое представление, поддерживается группа функций, посредством которых осуществляется весь доступ к набору.
Автор определения представления должен вносить необходимые изменения в каждую из этих функций. Это влечет за собой значительные расходы на сопровождение программ, а также не позволяет выполнять обновление с помощью языка запросов. В качестве альтернативы такому подходу можно выдвинуть подходящую систему правил. Преимущество второго подхода заключается в том, что для обеспечения семантики обновления снимка требуется задать только одно (или несколько) правил. Это намного проще, чем внесение изменений в набор функций.66
Элементы виртуального набора не обязаны иметь уникальный идентификатор, так как физически их не существует. Следовательно, вряд ли можно требовать, чтобы каждая запись в наборе обладала уникальным идентификатором, как это делается во многих существующих прототипах ООБД.67
Предложение 2.4: Показатели производительности не имеют почти ничего общего с моделями данных и не должны в них проявляться.
Основными параметрами, по которым оценивается производительность работы с использованием как SQL , так и спецификаций более низкого уровня, являются следующие показатели:
Эти вопросы не имеют ничего общего с моделью данных или с использованием языков высокого уровня типа SQL вместо навигационного интерфейса низкого уровня. Например, тактика кластеризации связанных объектов представляется как важная черта ООБД. Однако эта тактика использовалась в системах баз данных уже многие годы, например, являлась основным средством в большинстве методов доступа IMS . Следовательно, кластеризация является вопросом физического представления и не имеет ничего общего с моделью данных СУБД. Аналогично, с моделью данных не связаны решения о том, должна ли система строить индексы для уникальных идентификаторов, и следует ли ей буферизовать записи базы данных на клиентской машине или даже в пользовательском пространстве прикладной программы.При известном потоке запросов к базе данных следует пытаться достичь максимальной производительности. Действенность конкретных методов зависит от специфики приложений. Эти методы пригодны для любой системы баз данных.
Предложения, следующие из необходимости открытости системы
Обратим внимание на прикладной программный интерфейс (Applications Programming Interface – API ), посредством которого программа пользователя будет общаться с СУБД.Предложение 3.1: СУБД третьего поколения должны быть доступны из различных языков программирования высокого уровня.
Некоторые разработчики систем утверждают, что СУБД должна быть тесно привязана к определенному языку программирования. Например, они говорят, что функция должна возвращать один и тот же результат независимо от того, была ли она выполнена в программе пользователя для временных данных или внутри СУБД для стабильных данных. Этого можно достичь только в том случае, если модель выполнения СУБД идентична модели выполнения конкретного языка программирования. Авторы манифеста считают, что это неверный подход.
Во-первых, невозможно договориться, какой именно язык программирования следует использовать. Приложения кодируются и будут кодироваться на различных языках, и на горизонте пока не видно языка программирования Esperanto . Отсюда следует необходимость в многоязычной СУБД.
Имеется еще одна причина, по которой открытая СУБД должна быть многоязычной. СУБД должна предоставлять доступ для различных внешних прикладных подсистем, например, Lotus 1-2-3. Такие подсистемы будут кодироваться на различных языках программирования – вот еще один аргумент в пользу многоязычности.
Предложение 3.2: Язык “X с поддержкой стабильных данных” (для различных X ) является хорошей идеей. Языки будут поддерживаться над единой СУБД благодаря расширениям компилятора и (более или менее) сложной системе времени выполнения.
В интерфейсах систем второго поколения с языками программирования препроцессор использовался отчасти потому, что на ранней стадии разработчики СУБД не сотрудничали с разработчиками компиляторов. Более того, у сохранения независимости языка СУБД от языков программирования есть свои преимущества (например, СУБД и языки программирования можно независимо расширять и тестировать). Однако получавшиеся интерфейсы не отличались дружественностью и уже в 1977 году были охарактеризованы как “попытки приклеить яблоко к блину”.
Поставщики обычно концентрировали свои усилия на создании элегантного интерфейса между своими языками четвертого поколения и сервисами баз данных. Очевидно, что не менее элегантные интерфейсы можно создать и для универсальных языков программирования.
Во-первых, очень важно установить более точное соответствие между системами типов. Именно в этом состоит основная проблема современных реализаций встроенного SQL , а не синтаксиса SQL . Во-вторых, было бы хорошо предоставить возможность сделать любую переменную в программе пользователя стабильной. Значения стабильных переменных не утрачиваются даже после окончания работы программы. В последнее время проявляется большая заинтересованность в подобных интерфейсах.
Как отмечалось ранее, функции должны кодироваться путем включения вызовов к СУБД, выраженных на языке запросов. Следовательно, и для “X с поддержкой стабильных данных” также требуются средства выражения на языке запросов. Такие запросы могут быть выражены в нотации, соответствующей специфике языка программирования. Системы времени выполнения должны принимать и обрабатывать такие запросы и доставлять результаты обратно в программу.
Будет создано множество разнообразных “X с поддержкой стабильных данных”. Для каждого из них потребуются свои модификации компилятора и системы времени выполнения. Все системы времени выполнения будут подключены к общей СУБД.68 Очевиден вопрос “Как выражать запросы к этой общей СУБД?”. Ответ дается в следующем предложении.
Предложение 3.3: Хорошо это или плохо, но SQL становится интергалактическим языком данных.
На сегодня SQL предоставляет универсальный способ выражения запросов. При создании первых коммерческих объектно-ориентированных баз данных этот факт не учитывался, и потом пришлось встраивать в продукты запросные системы на основе запросов SQL . К сожалению, многие продукты не дожили до окончания этой работы. Хотя перед SQL и стоит множество мелких проблем, он необходим для коммерческой жизнеспособности. Любая компания-производитель объектно-ориентированных систем баз данных, желающая, чтобы ее продукт оказывал влияние на рынок, должна понять, что покупатели голосуют своими долларами за SQL .
Более того, SQL является разумной кандидатурой для новых функций, предлагаемых в этой работе. Конечно, для некоторых приложений и языков программирования могут оказаться адекватными и другие языки запросов.
Предложение 3.4: Запросы и ответы на них должны образовывать нижний уровень коммуникаций между клиентом и сервером.
В условиях, когда пользователь находится за рабочей станцией и взаимодействует с данными на удаленном сервере, встает вопрос о протоколах взаимодействия рабочей станции и сервера. Энтузиасты ООБД обсуждают, должны ли посылаться запросы на единичные записи, единичные страницы или должен использоваться иной механизм. Точка зрения авторов манифеста крайне проста: выражения на языке запросов должны образовывать нижний уровень коммуникаций. Конечно, если набор запросов можно упаковать в функцию, пользователь может использовать удаленный вызов для выполнения функции на сервере. Эта возможность желательна, поскольку она позволяет обойтись менее чем одним сообщением на запрос.
Принципы СУБД третьего поколения
Первый принцип касается определения СУБД третьего поколения: помимо традиционных услуг по управлению данными, СУБД третьего поколения должны обеспечивать поддержку более богатых структур объектов54 и правил.Более богатая структура объектов характеризует средства, необходимые для хранения и манипулирования нетрадиционными элементами данных (тексты, пространственные данные). Помимо этого, создателям приложений следует предоставить возможность задавать группу правил, касающихся элементов данных, записей и наборов.Ссылочная целостность в контексте реляционных баз данных представляет собой простой пример такого правила; однако существует множество более сложных правил.
Для успешного решения большинства задач СУБД должна предоставлять услуги в области данных, объектов и правил. Хотя, возможно, на рынке найдется ниша и для систем с меньшими возможностями, для достижения коммерческого успеха в 90-е годы СУБД должна предоставлять сервисы во всех трех перечисленных областях.55
Второй принцип: СУБД третьего поколения должны включить в себя СУБД второго поколения.
Системы второго поколения внесли решающий вклад в двух областях: непроцедурный доступ и независимость данных. И эти достижения не должны быть отброшены в системах третьего поколения.
Существует точка зрения, что имеются приложения, которым никогда не потребуется выполнять запросы из-за присущей им простоты доступа к СУБД. В качестве примера часто предлагаются САПР. Делается вывод, что будущим системам язык запросов не потребуется и, следовательно, отпадает необходимость включения систем второго поколения. Авторы Второго манифеста беседовали со многими разработчиками САПР, интересующимися базами данных, и все они отмечали необходимость языка запросов.
Другим улучшением, внесенным системами второго поколения, стало введение понятия независимости данных. В области физической независимости данных системы второго поколения автоматически поддерживают согласованность всех путей доступа к данным, и оптимизатор запросов автоматически выбирает лучший способ выполнения любой выданной пользователем команды.
Кроме того, системы второго поколения обеспечивают представления баз данных, посредством которых пользователь может быть изолирован от изменений анализируемого множества наборов, хранящихся в базе данных. Эти характеристики значительно снизили объем программной поддержки, которая должна быть обеспечена приложениями, и от них не стоит отказываться.
Третий принцип состоит в том, что СУБД третьего поколения должны быть открыты для других подсистем.
Иными словами, любая СУБД, рассчитывающая на широкую сферу применения, должна быть оснащена языком четвертого поколения (4GL )56, разнообразными инструментами поддержки принятия решений57, дружественным доступом из многих языков программирования, дружественным доступом из популярных подсистем, таких как LOTUS 1-2-3, интерфейсами с графическими бизнес-пакетами, возможностью запуска приложений из базы данных на другой машине и возможностью организации распределенной базы данных. Весь набор инструментов и СУБД должен эффективно функционировать на разнообразных аппаратных платформах с различными операционными системами.
Из этой посылки исходят два следствия. Во-первых, любая удачная система третьего поколения должна поддерживать большую часть перечисленного инструментария. Во-вторых, СУБД третьего поколения должны быть открытыми, то есть должны допускать реализацию доступа из дополнительных инструментов, функционирующих в различных средах. Более того, каждая система третьего поколения должна легко объединяться с другими СУБД для создания распределенных систем баз данных.
Промежуточные замечания
По мнению автора этой статьи, основной интерес в статье Дона Чемберлина представляет то, что в ней показана возможность создания нетрадиционных приложений при наличии минимальных объектных расширений в DB 2 for Common Servers . В частности, статья заставляет задуматься о том, нужны ли на самом деле дальнейшие расширения.Тем не менее, компания IBM выполнила практически все свои обещания, и ниже мы кратко обсудим дополнительные объектные расширения, реализованные в следующих версиях DB 2 UDB .
Размышления о будущем
Все возможности, описанные в статье [11], были доступны в DB 2 for Common Servers с июля 1995 г. IBM планировала распространить те же возможности и на других членов семейства DB 2. Особенно важно то, что через год после выпуска компанией IBM ее первой объектно-реляционной системы в лабораториях IBM производилась интенсивная разработка дополнительных объектно-реляционных средств, включая следующее:абстрактные типы данных с наследованием;
UDF с телом, написанным на SQL;
UDF, результатом которых являются таблицы;
возможность обращаться со строкой таблицы как с объектом, возможно содержащим ссылки на другие сроки-объекты;
дополнительные расширители для таких специализированных типов данных, как временные ряды и географические данные.
Синергия
Большие объекты, определяемые пользователями типы и функции, ограничения и триггеры представляют в отдельности мощные возможности. Но истинная объектно-реляционная мощность DB 2 происходит из синергии этих возможностей. В качестве примера рассмотрим, как объектно-реляционные возможности DB 2 могут быть использованы на обеспечения хранения в базе данных многоугольников.Поскольку отсутствует предопределенный тип данных “многоугольник”, то прежде всего нужно понять, каким образом многоугольники будут представляться в базе данных. Поскольку многоугольники потенциально могут быть довольно большими, для их представления должен использоваться тип больших объектов BLOB . Но хотелось бы отличить это представление от других объектов типа BLOB , и поэтому мы создадим индивидуальный тип POLYGON :
CREATE DISTINCT TYPE POLYGON AS BLOB(1M);
Можно выбрать различные реальные представления многоугольников внутри большого объекта. Например, это может быть последовательность чисел, первое из которых задает число вершин многоугольника, а следующие содержат координаты вершин. После создания индивидуального типа желательное поведение многоугольников может быть указано путем создания набора соответствующих UDF . По крайней мере, одна из этих функций должна быть “конструктором”, создающим многоугольник на основе более простых типов, таких как POINT или DOUBLE . Работа функции-конструктора состоит в упаковке примитивных частей многоугольника в BLOB с последующим преобразованием типа BLOB к типу POLYGON (для этого следует использовать сгенерированную системой функцию преобразования типов POLYGON ( BLOB )) . Ниже перечислены некоторые из UDF , задающие поведение типа POLYGON . Эти функции могут быть написаны, например, на языках C или C ++.
degree(Polygon) returns Integer;
area(Polygon) returns Double;
perimeter(Polygon) returns Double;
rotate(Polygon, Double) returns Polygon;
intersect(Polygon, Polygon) returns Polygon;
Теперь можно создавать таблицы со столбцами типа POLYGON . Например, следующий оператор можно было бы использовать в налоговом управлении для создания таблицы, в которой должны регистрироваться земельные участки, находящиеся в частной собственности:
CREATE TABLE properties
(taxid Char(6) PRIMARY KEY,
owner Varchar(32),
assessment Dollars,
parcel Polygon );
Для нахождения собственников больших участков можно использовать следующий запрос на языке SQL :
SELECT owner, area(parcel)
FROM properties
WHERE area(parcel) > 20000;
Наиболее эффективный способ выполнения этого запроса мог бы базироваться на использовании индекса, обеспечивающего прямой доступ к участкам по значению их площади. Поддержка индексов на UDF находится в планах развития DB 2, но пока ее нет. Но возможно другое решение, позволяющее выполнить запрос с той же эффективностью. Добавим к таблице PROPERTIES новый столбец, который должен содержать заранее вычисленный размер площади, и создадим триггеры для поддержки корректных значений этого столбца. Для добавления столбца можно использовать оператор SQL
ALTER TABLE properties
ADD COLUMN area Double;
Теперь определим триггеры, которые активируются при выполнении над таблицей PROPERTIES операторов INSERT и UPDATE . Вот как могло бы выглядеть определение триггера для INSERT :
CREATE TRIGGER insertprop
NO CASCADE
BEFORE INSERT ON properties
REFERENCING NEW AS newrow
FOR EACH ROW MODE DB2SQL
SET newrow.area = area(newrow.area);
Поскольку площадь каждого участка автоматически вычисляется и хранится в отдельном столбце, для убыстрения доступа к участкам по значению их площади можно создать индекс на столбце AREA :
CREATE INDEX proparea ON properties(area);
Теперь перепишем запрос в форме, которая даст возможность DB 2 использовать этот индекс:
SELECT owner, area
FROM properties
WHERE area > 20000;
Составные типы данных
IUS позволяет определять новые составные типы данных. Составные типы могут иметь структуру записи, множества, мультимножества или списка. Структуры данных могут быть вложенными, то есть значениями столбцов таблиц могут быть записи83, множества или списки, состоящие в свою очередь из атомарных или структурных значений.Например, значениями следующего типа данных являются ФИО человека:
CREATE ROW TYPE fio_t
( last_name CHAR(40),
first_name CHAR(40),
second_nameCHAR(40) )
Определенный таким образом составной тип может использоваться наравне и с предопределенными типами для определения столбцов таблицы. Для доступа к отдельным полям значений типа записи используется традиционная “точечная” нотация.
Имеется возможность определения трех видов типов коллекций: множеств, мультимножеств и списков (иными словами, имеются конструкторы этих типов). Поскольку по определению все элементы множества должны быть различны, ни в одно значение типа множества не может входить NULL 84.
Хотя по определению среди элементов мультимножества могут содержаться дубликаты, в IUS значения типа мультимножества, как и значения-множества не могут содержать неопределенных значений.85
Средствами прямого SQL можно осуществлять доступ к значениям-множествам (и мультимножествам) только как к единому целому. Доступ к элементам множества возможен только при использовании встроенного SQL (вернее, варианта SQL , поддерживаемого в IUS ) или языка определения хранимых процедур (SPL ). Основная идея состоит в том, что множество представляется в виде производной таблицы, каждая строка которой содержит один элемент множества. Любую операцию с множествами можно выразить в терминах реляционных операций над производными таблицами.
Список является упорядоченным набором элементов, в котором допускается наличие дубликатов. Список отличается от мультимножества тем, что для каждого элемента списка имеется порядковый номер (нумерация начинается с единицы). В значениях-списках, как и в значениях-множествах (и мультимножествах), запрещается наличие элементов со значением NULL .86 Доступ к элементам значений-списков столбцов таблицы базы данных, как и к значениям-множествам и мультимножествам, обеспечивается только при использовании встроенного SQL или SPL .
Создание иерархий таблиц
Иерархии таблиц используются для хранения объектов и для обеспечения возможности изменять эти объекты на уровне SQL . С концептуальной точки зрения, в иерархии таблиц отражается соответствующая иерархия типов. Однако типы, подобно библиотекам классов, могут использоваться в различных контекстах, поэтому не все типы из иерархии типов обязаны присутствовать в соответствующей иерархии таблиц. Единственным требованием является то, что при образовании иерархии таблиц должно использоваться подмножество ассоциированной иерархии типов.При определении типизированной таблицы нужно явно специфицировать дополнительный столбец, в котором будут храниться значения объектных идентификаторов (OID ) каждого объекта (строки), содержащейся в таблице. Столбец OID создается как первый столбец таблицы, и за ним следуют столбцы, соответствующие атрибутам типа таблицы. Объектные идентификаторы используются в операциях разыменования (dereference ), т.е. обеспечивают возможность добраться до строки по ссылке и преобразовать ее в экземпляр (значение) структурного типа. Объектные идентификаторы относятся к ссылочному типу. Они строго типизированы (т.е. для них не допускаются неявные преобразования типов). Чтобы преобразовать один ссылочный тип в другой, требуется промежуточное преобразование OID к одному из базовых типов.
Специальные методы хранения, поиска и индексации
В IUS можно определять новые базовые типы данных одновременно с введением специальных алгоритмов хранения, доступа и индексирования, которые отличаются от стандартных алгоритмов, реализованных в сервере87. Для введения нового базового типа данных с нестандартными методами доступа нужно определить набор серверных функций, реализующий для нового типа алгоритмы доступа, просмотра, выделения памяти и т.д. Эти функции должны быть написаны на языке C и скомпилированы в объектный формат. Далее надо описать новый базовый тип данных, и указать функции, реализующие для этого типа алгоритмы извлечения и записи на диск значений данного типа.Ссылочные значения и REF -типы
Понятия ссылочных значений и ссылочных (REF ) типов являются по существу неразделимыми. В SQL :1999 ссылочный тип может использоваться в качестве типа данных столбцов обычных таблиц, атрибутов структурных типов и т.д. – словом, везде, где можно использовать другие типы данных SQL . Значения местоположений ссылочного типа всегда являются ссылочными значениями строк типизированных таблиц (т.е. значениями самоссылающихся столбцов этих строк).В SQL :1999 обеспечиваются три механизма назначения уникальных идентификаторов экземплярам структурных типов, ассоциированных с типизированными таблицами. Во всех типизированных таблицах, ассоциированных с данными структурным типом, должен использоваться один и тот же механизм. Предоставляются следующие альтернативы выбора ссылочных значений, которые могут являться
значениями некоторого встроенного типа SQL , которые должны генерироваться приложением каждый раз при сохранении экземпляра структурного типа как строки типизированной таблицы;
значениями, порождаемыми из одного или нескольких атрибутов структурного типа;
значениями, автоматически генерируемыми системой.
При определении структурного типа, который предназначается для определения одной или нескольких типизированных таблиц, необходимо задать спецификацию ссылочного типа. При определении типизированных таблиц, необходимо указать соответствующую спецификацию самоссылающегося столбца (конечно, эта спецификация логически избыточна).
Если для некоторого структурного типа выбран вариант пользовательской генерации ссылочных значений, то ответственность за поддержание уникальности таких значений лежит на пользователе. Конечно, ограничения PRIMARY KEY или UNIQUE , определенные на уровне максимальной супертаблицы семейства типизированных таблиц, могут гарантировать отсутствие в любой таблице этого семейства дублирующих ссылочных значений, но в SQL :1999 отсутствуют какие-либо средства, предотвращающие повторное использование ссылочных значений из удаленных строк в самоссылающихся столбцах новых строк.
В этом случае в определении структурного типа может присутствовать конструкция, специфицирующая функции преобразования значений встроенного типа в значения ссылочного типа и наоборот. В этой конструкции вводятся имена двух SQL -функций, первая из которых служит для преобразования ссылочных значений (в нашем примере, значений целого типа), обеспечиваемых приложением, к соответствующему REF -типу при вставке или обновлении строк типизированной таблицы. Вторая функция преобразует значения REF -типа к соответствующему встроенному типу данных при выборке строк из типизированной таблицы. Система автоматически генерирует обе подпрограммы, и упомянутая конструкция позволяет лишь назначить подпрограммам имена. Если эта конструкцияявно не включается в определение структурного типа со ссылочными значениями, генерируемыми пользователями, то имена подпрограммам назначаются системой.
Если для структурного типа выбирается альтернатива порождения ссылочных значений, то система использует для порождения ссылочных значений значения неявно указанных столбцов (соответствующих явно указанным атрибутам ассоциированного структурного типа). При этом остаются все упомянутые выше проблемы, хотя в этом случае явно требуется объявление ограничений PRIMARY KEY или UNIQUE для соответствующего набора столбцов.
Наконец, при выборе последней альтернативы (системно-генерируемые ссылочные значения) каждой строке, вставляемой в типизированную таблицу, ассоциированную с соответствующим структурным типом, присваивается уникальный идентификатор. Это значение сохраняется в самоссылающемся столбце и может быть использовано любым приложением для уникальной идентификации данной строки во все время жизни таблицы.
Самоссылающиеся столбцы всегда имеют REF -тип. Конкретный REF -тип зависит от двух факторов:
структурного типа, ассоциированного с типизированной таблицей: REF -тип всегда связан с некоторым структурным типом;
от выбранного способа генерации ссылочных значений; эта информация задается в определении структурного типа и не присутствует в спецификации ссылочного типа.
В спецификации ссылочного типа задается имя структурного типа, на экземпляры которого будут указывать значения ссылочного типа (referenced type ). REF -тип может использоваться в качестве типа атрибута структурного типа, и в этом случае referenced _ type может быть тем же самым, что и определяемый структурный тип. Во все остальных случаях referenced _ type должен являться некоторым существующим структурным типом.
В необязательном разделе указания области действия значений ссылочного типадолжно задаваться имя типизированной таблицы, ассоциированным структурным типом которой является referenced _type REF -типа, в спецификации которого содержится этот раздел. Ассоциированный структурный тип таблицы, на строки которой указывают значения REF -типа, должен быть в точности тем же, что и referenced _type этого REF -типа. Но можно объявить REF -тип, у которого referenced _type является ассоциированным структурным типом подтаблицы, хотя самоссылающийся столбец этой подтаблицы необходимо наследуется от максимальной супертаблицы семейства таблиц.
Если раздел указания области действия значений действительно присутствует, то требуется также указать, нужна ли проверка ссылочных значений.
Если проверка не требуется, то в определяемом столбце можно хранить любое ссылочное значение, независимо от того, является ли оно значением самоссылающегося столбца какой-либо таблицы на строку, которой предположительно указывает ссылка. В этом случае система не гарантирует, что ссылочное значение действительно указывает на строку (но, конечно, это значение должно быть значением правильного типа – REF -типа указанного структурного типа).
Если же указывается потребность в проверке, то каждый раз при сохранении значения в определяемом столбце система обращается к указанной таблице, чтобы убедиться в том, что в ней имеется строка, значение самоссылающегося столбца которой совпадает с сохраняемым ссылочным значением. Кроме того, в этом случае можно также указать ссылочное действие, которое должно выполняться при удалении строки, идентифицируемой ссылочным значением.
Возможными ссылочными действиями являются RESTRICT , CASCADE , SET NULL и NO ACTION . Если ссылочное действие явно не указывается, по умолчанию принимается NO ACTION .
Заметим, что если раздел указания области действия значенийвключается в определение атрибута структурного типа, то соответствующий раздел не может присутствовать среди опций столбца типизированной таблицы, соответствующего данному атрибуту.
Выборка данных из типизированных таблиц
Приведем несколько примеров операций выборки данных из типизированных таблиц, а также операций обновления таких таблиц. Для этого сначала определим структурные типы EMP _ T , PROGRAMMER _ T и DEPT _ T , а также соответствующие типизированные таблицы (упрощенный вариант).
CREATE TYPE EMP_T AS (
EMP_NAME VARCHAR(20),
EMP_BDATE DATE,
EMP_SAL SALARY,
DEPT REF (DEPT) )
INSTANTIABLE
NOT FINAL
REF IS SYSTEM GENERATED
INSTANCE METHOD age ()
RETURNS DECIMAL (3,1)
CREATE TYPE PROGRAMMER_T UNDER EMP_T AS (
PROG_LANG VARCHAR (10) )
INSTANTIABLE
NOT FINAL
CREATE TYPE DEPT_T AS (
DEPT_NO INTEGER,
DEPT_NAME VARCHAR(200),
DEPT_MNG REF (EMP) )
INSTANTIABLE
NOT FINAL
CREATE TABLE EMP OF EMP_T
( REF IS DEPT_ID SYSTEM GENERATED,
DEPT WITH OPTIONS SCOPE DEPT )
CREATE TABLE PROGRAMMER OF PROGRAMMER_T UNDER EMP
CREATE TABLE DEPT OF DEPT_T
( REF IS EMP_ID SYSTEM GENERATED,
DEPT_MNG WITH OPTIONS SCOPE EMP )
Во-первых, заметим, что с типизированными таблицами можно работать как с обычными таблицами. Поэтому, частности, возможен следующий запрос.
Пример 3.1. Найти имена всех служащих, размер заработной платы которых меньше 20000.00.
SELECT EMP_NAME
FROM EMP
WHERE EMP_SAL < 20000.00
В соответствии с семантикой SQL :1999, при выполнении запроса из прим. 3.2 сначала будет произведена выборка имен служащих, удовлетворяющих условию, из таблицы EMP , затем – из таблицы PROGRAMMER , и эти промежуточные результаты будут скомбинированы в окончательный результат путем применения операции объединения ( UNION ).
Но предположим, что нас интересуют только те служащие, получающие зарплату, меньшую 20000.00, которые не являются программистами (пример 3.2). Тогда можно применить формулировку запроса, в которой присутствует спецификация ONLY :
SELECT EMP_NAME
FROM ONLY ( EMP )
WHERE EMP_SAL < 20000.00
Естественно, в запросах к типизированным таблицам можно использовать ссылки.
Пример 3.3. Найти имена и названия отделов всех служащих, размер заработной платы которых меньше 20000.00.
SELECT EMP_NAME, DEPT -> DEPT_NAME
FROM EMP
WHERE EMP_SAL < 20000.00
В SQL :1999 операция “ -> ” называется операцией разыменования , но в обиходе можно считать ее операцией перехода по ссылке (в нашем примере DEPT ссылается на DEPT _ NAME ). Можно неформально трактовать ссылочные значения как указатели на строки типизированных таблиц.
Может показаться неожиданным, что запрос из прим. 3.3 выбирает значения из таблицы DEPT , хотя она даже не упоминается в разделе FROM этого запроса. Дело в том, что выполнение операции разыменования фактически приводит к выполнению соединения таблиц EMP и DEPT , делая “видимым” в запросе столбец DEPT _ NAME .
Конечно, в запросе допускаются многократные переходы по ссылкам, так что можно сформулировать следующий запрос:
Пример 3.4. Найти имена служащих и имена руководителей их отделов для служащих, получающих зарплату, меньшую 20000.00.
SELECT EMP_NAME, DEPT -> DEPT_MNG -> EMP_NAME
FROM EMP
WHERE EMP_SAL < 20000.00
Как показывает следующий пример, в запросах можно использовать вызовы методов над строками, к которым производится переход по ссылке.
Пример 3.5. Найти имя и возраст руководителя отдела 605.
SELECT DEPT_MNG -> EMP_NAME, DEPT_MNG -> age ()
FROM DEPT
WHERE DEPT_NO = 605
Наконец, имеется возможность полностью выбрать экземпляр структурного типа, идентифицируемый ссылочным значением (в SQL :1999 это называется разрешением ссылки – reference resolution ).
Пример 3.6. Получить полные данные о руководителе отдела 605.
SELECT DEREF ( DEPT_MNG )
FROM DEPT
WHERE DEPT_NO = 605
В этом случае результатом запроса будет являться таблица, включающая один столбец структурного типа EMP _ T . Единственным значением этого столбца будет являться экземпляр (значение) этого структурного типа, соответствующий служащему-руководителю отдела 605.
Операции обновления типизированных таблиц выполняются очевидным образом. Операция INSERT вставляет указанные строки в указанную таблицу. Операции DELETE и UPDATE удаляют или модифицируют строки в иерархии таблиц, корнем которой является указанная таблица, если в операции не содержится ONLY . Если же специфицировано ONLY , то удаляются или модифицируются только строки указанной таблицы.
Структура, поведение, наследование
Для некоторых типов данных имеет смысл трактовать объект как именованный набор атрибутов. Этот вид определяемого пользователями типа в терминологии IBM называется структурным типом. Его поддержка появилась в DB 2 UDB Version 5.2 в 1998. Механизм структурных типов с самого начала включал не только возможность определения типов со структурой, но и средства определения иерархий типов и иерархий таблиц. Кроме того, допускалось использование “ссылок” для определения связей между объектами и навигации от одного объекта к другому.Для определения поведения структурного типа можно было использовать UDF . Однако в DB 2 Version 7 появилась возможность определения методов объектов. Методы очень похожи на UDF в том отношении, что они могут быть написаны на SQL или на внешнем языке, например, на Java или C . Но методы всегда ассоциируются с некоторым структурным типом, и их вызовы производятся в синтаксисе, отличном от синтаксиса вызова UDF .
Любая объектно-реляционная возможность DB 2 может быть использована в традиционном SQL . Чем дальше, тем увереннее можно говорить, что “традиционным” SQL в контексте DB 2 является SQL :1999. В одном приложении может потребоваться всего лишь поддержка LOB , а в другом могут понадобиться структурные типы, методы и наследование. Возможно даже использование объектно-ориентированного моделирования реляционных данных на основе объектных представлений.
Синтаксис оператора создания определяемого пользователем структурного типа очень поход на синтаксис оператора определения таблицы – указываются имя типа, имена его атрибутов и типы данных этих атрибутов. При создании подтипов структурного типа эти подтипы автоматически наследуют атрибуты супертипа.
Типизированные представления
Наряду с типизированными базовыми таблицами в SQL :1999 поддерживаются типизированные представления, иначе называемые представлениями, на которые можно ссылаться ( referenceable views ). Иногда такие представления также называют объектными представлениями, поскольку данные, видимые через представление, соответствуют строкам типизированных таблиц, поведение которых во многом похоже на поведение объектов в объектно-ориентированных системах. Между типизированными базовыми таблицами и типизированными представлениями имеется большое сходство, но есть и несколько отличий, связанных с врожденными различиями базовых таблиц и представлений.В SQL в связи с объектными представлениями вводится ряд терминов – суперпредставление, подпредставление, непосредственное суперпредставление, непосредственное подпредставление, собственное суперпредставление и собственное подпредставление. Смысл этих терминов полностью аналогичен смыслу соответствующих терминов для типизированных базовых таблиц. Термин семейство подтаблиц применяется по отношению и типизированных таблиц, и типизированных представлений.
При определении типизированного представления указывается имя существующего структурного типа. Как и в определении обычных представлений, специфицируется выражение запроса. В случае типизированных представлений это выражение запроса должно основываться на единственной типизированной таблице (базовой таблице или представлении). Эта типизированная таблица должна быть ассоциирована с тем же структурным типом, что и определяемое представление. Такую таблицу называют базисной таблицей представления.
Типизированное представление можно определить как подпредставление другого типизированного представления. В этом случае структурный тип, ассоциированный с определяемым представлением, должен являться непосредственным подтипом структурного типа, ассоциированного со специфицируемым в разделе UNDER суперпредставлением. Базисная таблица определяемого представления должна являться собственной подтаблицей или собственным подпредставлением – не обязательно непосредственным – базисной таблицы непосредственного суперпредставления определяемого представления.
В определение типизированного представления может входить один или несколько элементов, задающих область действия ссылочных значений столбцов REF -типов. Если представление определяется как подпредставление другого типизированного представления, то в его определении не должна содержаться спецификация самоссылающегося столбца. Если определяется максимальное суперпредставление, то эта спецификация может, но не обязана присутствовать. Если спецификация присутствует, то она может содержать только генерируемые пользователями или порождаемые ссылочные значения (из этого следует, что нельзя определить типизированные представления, в ассоциированном структурном типе которого присутствует спецификация системно-генерируемых ссылочных значений) .
[] [] []
document.write('');
| This Web server launched on February 24, 1997 Copyright © 1997-2000 CIT, © 2001-2009 |
| Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. |
|
Предложение от профессионалов: от компании «Монтажпищепром». |
Типизированные таблицы
В предыдущем подразделе уже упоминалась возможность определения типизированных таблиц, основанных на некотором структурном типе. Здесь мы приведем и поясним понятие иерархии типизированных таблиц и связь этой иерархии с иерархией структурных типов, а также обсудим соотношение понятие строки типизированной таблицы с понятием объекта в ООБД.поддерживаются две разновидности типов
В Oracle 8 поддерживаются две разновидности типов коллекций: табличные типы (table types) и типы массивов. Значениями каждого типа коллекции являются коллекции (таблицы или массивы) элементов одного и того же типы (типа элемента). Тип элемента может быть встроенным или объектным типом, но не типом коллекции. Поскольку табличный тип является оригинальным изобретением компании Oracle, остановимся на нем немного подробнее. Табличный тип создается конструкцией следующего вида:CREATE TYPE < имя типа > AS TABLE OF < тип элемента >;
Например, при наличии определения объектного типа EMP _ T можно было бы определить табличный тип DEPENDENTS _ T следующим образом:
CREATE TYPE DEPENDENTS_T AS TABLE OF EMP_T;
После этого можно определить таблицу BOSSES, содержащую столбец, значениями которого являются таблицы, которые содержат данные о подчиненных служащего:
CREATE TABLE BOSSES
( boss EMP_T,
dependentsEMP_T,
PRIMARY KEY ( boss.EMP_NO ) )
Nested TABLE DEPENDENTS STORE AS DEPENDENTS_TAB;
В результате выполнения этой операции в базе данных будут созданы две таблицы – таблица верхнего уровня BOSSES и вложенная таблица DEPENDENTS _ TAB , содержащая все строчные объекты, которые соответствуют сотрудникам-подчиненным. Конечно, если в таблице верхнего уровня имелось бы несколько столбцов табличного типа, то для каждого из этих столбцов потребовался бы свой раздел Nested TABLE . П родемонстрируем возможность выборки из таблицы с вложенной подтаблицей на примере.
Пример 3.7. Выбрать из таблицы BOSSES все пары “начальник-подчиненный”.
SELECT B.boss.EMP_NO, D.EMP_NO
FROM BOSSES B, TABLE ( B.dependents) D
Должно быть понятно, что этот запрос в сокращенной форме выражает естественное соединение таблиц BOSSES и DEPENDENTS _ TAB . Поэтому в результате не появятся данные о служащих, данные о которых включены в таблицу BOSSES и которые не имеют подчиненных. Чтобы получить данные обо всех сотрудниках, данные о которых включены в таблицу BOSSES , в синтаксисе SQL Oracle 8 требуется задать следующий запрос:
SELECT B.boss.EMP_NO, D.EMP_NO
FROM BOSSES B, TABLE ( B.dependents ) (+) D
Этот запрос соответствует требованию правого внешнего естественного соединения. Во встроенном SQL Oracle 8 имеются и другие способы доступа к вложенным таблицам, которые мы не будем обсуждать в этой статье.
Вторая разновидность типов коллекций в Oracle 8 называется VARRAY , что вполне соответствует стандарту SQL :1999 и означает “массив переменного размера” (varying -length array ). При определении типа массива указываются имя типа, тип элементов и максимальное число элементов, которые может содержать значение определяемого типа. В отличие от значений табличного типа, для элементов значений типа массива поддерживается порядок.
Как и в случае с множествами (и мультимножествами) в IUS, на уровне прямого SQL в Oracle можно работать только с массивами целиком. Однако существует возможность привести в запросе (или другом операторе SQL) тип массива к табличному типу.
Типы коллекций
Начиная с SQL :1999, в языке поддерживается возможность использования типов данных, значения которых являются коллекциями значений некоторых других типов. Обычно под термином коллекция понимается одно из следующих образований: массив, список, множество и мультимножество. В варианте SQL :1999, принятом в 1999 г., специфицированы только типы массивов. Любой возможный тип массива получается путем использования конструктора типов ARRAY . При определении столбца, значения которого должны принадлежать некоторому типу массива, используется конструкцияdt ARRAY [ mc
] , где dt специфицируетнекоторый допустимый в SQL тип данных (отличный от типа массива), а mc является литералом некоторого точного числового типа с нулевой длиной шкалы и определяет максимальное число элементов в значении типа массива (в терминологии SQL :1999 это значение называется максимальной кардинальностью массива). Тем самым, в текущей версии стандарта SQL :1999 не поддерживаются многомерные массивы и массивы массивов.
Элементам каждого значения типа массива соответствует их порядковый номер, называемый индексом. Значение индекса всегда должно принадлежать отрезку [1, mc ]. Значениями типа массива dt ARRAY [ mc ] являются все те массивы, состоящие из элементов типа dt , максимальное значение индекса которых cs не превосходит значения mc . При сохранении в базе данных значение типа массива занимает столько памяти, сколько требуется для сохранения cs элементов. Обеспечивается доступ к элементам массива по их индексам. В частности, можно объявить столбец типа INTEGER ARRAY [10] и при вставке строки в соответствующую таблицу задать значение только пятого элемента массива. Тогда в строку будет занесен массив из пяти элементов, причем первые четыре элемента будут содержать неопределенное значение (NULL ).
Основными операциями над массивами являются выборка значения элемента массива по его индексу, изменение некоторого элемента массива или массива целиком и конкатенация (сцепление) двух массивов. Кроме того, для любого значения типа массива можно узнать значение его cs .
Точка зрения компании IBM относительно ОРСУБД
Традиционные возможности языка SQL , связанные с типами данных и поиском, недостаточны для нового поколения мультимедийных приложений баз данных. Также понятно, что требования таких приложений настолько различны, что не могут быть удовлетворены любым набором предопределенных расширений языка. Требуются средства определения пользователями новых типов данных и функций над ними.Другим требованием современных приложений баз данных является возможность хранения правил, делающих данные более активными и позволяющих системе баз данных автоматически выполнять проверки корректности данных и автоматизировать многие бизнес-процедуры. Активизация данных дает возможность приложениям совместно использовать не только сами данные, но и поведение данных.
Обе указанные возможности позволяют повысить ценность хранимых данных за счет расширения их семантического содержимого. Тенденция к повышению роли семантического содержимого хранимых данных является наиболее важной в современном управлении базами данных. В соответствии с этой тенденцией реляционные системы баз данных расширяются в двух направлениях: (1) добавлении “объектной инфраструктуры” к самой системе баз данных в виде поддержки определяемых пользователями типов данных, функций и правил; (2) построении поверх этой инфраструктуры “реляционных расширителей”, которые поддерживают специализированные приложения, такие как выборка изображений, развитый текстовый поиск, географические приложения. Система, которая обеспечивает объектную инфраструктуру и набор реляционных расширителей, называется “объектно-реляционной”.
Тринадцать предложений
Во Втором манифесте выдвигались три группы детальных предложений, которым, по мнению авторов манифеста, должны были следовать удачные образцы систем баз данных третьего поколения 90-х годов. Предложения первой группы следуют из принципа 1 и уточняют требования к управлению объектами и правилами. Во второй группе содержится набор предложений, являющихся следствием того, что системы третьего поколения должны включать в себя системы второго поколения. Наконец, в третью группу сведены предложения, исходящие из требования открытости систем третьего поколения.Второй манифест
Авторы Второго манифеста относят к первому поколению систем баз данных предшествовавшие РСУБД иерархические и сетевые системы, а существовавшие во время написания манифеста реляционные системы – ко второму поколению. В документе рассматриваются характеристики, которыми должны обладать менеджеры баз данных следующего, уже третьего поколения. Требования состоят из трех основных принципов и тринадцати детальных предложений.Заключение к разделу
Если обратиться к истории, то обнаружится, что попытки расширения функциональности СУБД, изначально основанных на реляционном подходе, предпринимались уже на ранних стадиях разработки таких систем. Классическими примерами являются проекты System R (IBM ), где пытались обеспечить возможности работы со сложными объектами путем расширения SQL [27], и Ingres (университет Беркли), где Майкл Стоунбрейкер предлагал механизм определения пользовательских типов данных на основе представлений и хранимых процедур [28]. Однако новый толчок к расширению SQL -ориентированных СУБД объектными свойствами был получен со стороны объектного мира после публикации Первого манифеста.В ответном Втором манифесте индустрия развитых СУБД утверждала, что имеются реальные возможности добиться желаемой функциональности без коренной ломки традиционной технологии. Идеи Второго манифеста были воплощены в жизнь в нескольких ведущих SQL -продуктах, и использование объектных расширений позволило самим поставщикам обеспечить ряд законченных функциональных расширений своих систем. Однако ожидания большого спроса на сами инструменты объектных расширений со стороны пользователей не оправдались. Некоторые известные специалисты из области баз данных считают, что для этого еще не пришло время.
Развитие объектно-реляционного подхода отразилось в соответствующем развитии языка SQL . Гигантский стандарт SQL :1999 позволяет хотя бы сопоставлять отдельные реализации, хотя ни одна компания полностью его не поддерживает.
Заключение Второго Манифеста
Авторы Манифеста баз данных следующего поколения во многом согласны с энтузиастами ООБД. Среди общих тем выделяются выгодность использования богатой системы типов, функций, наследования и инкапсуляции. Однако во многих областях позиции прямо противоположны. Во-первых, Манифест объектно-ориентированных баз данных слишком узко сфокусирован на вопросах управления объектами. Авторы Второго манифеста обращаются к более широкому кругу вопросов, включающих поддержку управления данными, правилами и объектами на основе полного набора инструментов при наличии интеграции СУБД и языка запросов в многоязычную среду. Предлагаемые многими энтузиастами ООБД одноязычные системы, не поддерживающие SQL , привлекательны лишь для довольно узкого рынка.Во-вторых, представляется, что доступ к СУБД должен осуществляться при помощи языка запросов, и история подтверждают правильность такой точки зрения. Следует избегать физической навигации, выполняемой программами пользователей или происходящей внутри функций. В-третьих, необходимо всячески поощрять использование автоматических наборов, так как они предоставляют массу преимуществ по сравнению с явно поддерживаемыми наборами. В-четвертых, свойство стабильности данных может быть добавлено ко многим языкам программирования. Поскольку не существует языка программирования, аналогичного эсперанто, этого следует достигать путем изменения компилятора и написания специфичной для языка системы времени выполнения, взаимодействующей с единой СУБД. Таким образом, языки программирования с поддержкой стабильных данных мало связаны с моделями данных. В-пятых, уникальные идентификаторы должны задаваться либо пользователем, либо системой (здесь наличествует противоречие с одним из принципов Первого манифеста).
Основной вопрос, по которому авторы Второго манифеста расходились во мнениях с большей частью сообщества ООБД, – это возможность естественной эволюции современных реляционных систем к системам, поддерживающим возможности, обсуждаемые в данной работе.
Авторы данного манифеста верили в такую возможность. Уже в то время продукты основных поставщиков реляционных систем удовлетворяли принципам 1, 2 и 3 и обеспечивали хорошую поддержку предложений 1.3, 1.4, 1.5, 2.1, 2.3, 2.4, 3.1, 3.3 и 3.4. Для превращения в СУБД третьего поколения в эти продукты оставалось добавить наследование и дополнительные конструкторы типов и внедрить языки программирования с поддержкой стабильных данных. Существовали прототипы систем, указывающие пути включения и этих средств.
С другой стороны, современные (в то время) системы, провозглашаемые объектно-ориентированными, обычно не соответствуют провозглашаемым во Втором манифесте принципам и поддерживают лишь предложения 1.1 (частично), 1.2, 1.3 и 3.2. Для превращения в подлинные СУБД третьего поколения таким системам не хватает языка запросов и оптимизатора запросов, системы правил, поддержки SQL в архитектуре клиент-сервер, поддержки представлений и языков программирования со стабильными данными. Кроме того, в них должны быть отменены любые жесткие требования наличия уникальных идентификаторов и прекращено поощрение навигации. Более того, в них необходимо построить языки четвертого поколения, внедрить поддержку распределенных баз данных и осуществить настройку системы для эффективного управления данными.
Конечно, воплотить предложения манифеста непросто – придется столкнуться со многими проблемами. Создание языка с поддержкой стабильных данных для разнообразных языков программирования – труднейшая задача. Другую проблему представляет включение в такие языки приемлемых конструкций языка запросов. Далее, логическое и физическое проектирование баз данных для современных реляционных систем считается непростой задачей, а с внедрением более богатой системы типов и правил она еще более усложнится. Для помощи пользователю здесь потребуются методологии и инструменты проектирования баз данных. Серьезную трудность представляет оптимизация выполнения правил. Кроме того, для успеха новых технологий крайне важна визуализация и отладка ориентированных на правила приложений.
Три манифеста баз данных ретроспектива и перспективы
и T' должны быть типами;
T и T' должны быть типами; то есть каждый из них должен быть именованным множеством значений.Каждое значение T' должно быть значением T; то есть множество значений, составляющих T', должно быть подмножеством множества значений, составляющих T (другими словами, если значение принадлежит типу T', то оно также должно принадлежать типу T). Более того, если T и T'
различны (см. IM-предписания 3 и 4), то должно существовать по крайней мере одно значение, которое принадлежит типу T
и не принадлежит типу T'.
T и T' не обязательно должны быть различны; то есть, каждый тип должен быть как подтипом, так и супертипом самого себя.
Если и только если типы T и T'
различны, то T' является собственным подтипом T, и T
является собственным супертипом T'.
Каждый подтип T' должен быть подтипом T. Каждый супертип T должен быть супертипом T'.
Если и только если T' является собственным подтипом T и не существует типа, который одновременно является собственным супертипом T' и собственным подтипом T, то T' является непосредственным подтипом T, а T является непосредственным супертипом T'. Тип, который не является непосредственным
подтипом какого-либо типа, является корневым
типом. Тип, который не является непосредственным
супертипом какого-либо типа, является листовым типом.
( Вариант, предполагающий множественное наследование )
Если типы T1 и T2 являются различными корневыми типами, то они должны быть непересекающимися; то есть никакое значение не должно одновременно принадлежать типу T1 и типу T2.
( Вариант, предполагающий множественное наследование )
Для каждого набора скалярных типов T1, T2, …, Tn (n>0) должен иметься общий подтип T' такой, что заданное значение принадлежит каждому из типов T1, T2, …, Tn, если и только если оно принадлежит типу T'.
Пусть скалярная переменная V относится к объявленному типу T. По причине возможности замены значений (см. IM-предписание 16) значение v, присвоенное V , в любой момент времени может принадлежать любому подтипу T' типа T как своему наиболее конкретному типу. Поэтому можно моделироватьV как именованный упорядоченный триплет вида
DT является именем объявленного типа переменной V;
v является значением наиболее конкретного типа – текущим значением (для)переменной V.
Обозначения DT(V), MST(V), v(V) используются для ссылок на компоненты DT, MST и v этой модели скалярной переменной V
соответственно.
Далее, пусть X - скалярное выражение. Систему обозначений DT(V), MST(V), v(V) можно очевидным образом расширить для ссылок на объявленный тип DT(X), текущий наиболее конкретный тип MST(X) и текущее значение v(X) выражения X соответственно, где “объявленный тип” – это то, что разъяснялось в RM-предписании 3, и этот тип известен во время компиляции, а “текущий наиболее конкретный тип” и “текущее значение” относятся к результату вычисления X и поэтому в общем случае неизвестны до времени выполнения.
Пусть T - регулярный собственный супертип (см. IM-предписание 20), и пусть T' - непосредственный подтип T. Тогда в определении T' должно специфицироваться ограничение специализации SC, сформулированное в терминах T и такое, что значение типа T должно принадлежать типу T', если и только если оно удовлетворяет ограничению SC. Должно существовать по крайней мере одно значение типа T, которое не удовлетворяет ограничению SC.
Пусть X - выражение. Рассмотрим присваивание
V := X
;
(где V является переменной). DT(X) должно быть подтипом DT(V). Присваивание должно сделать MST(V) равным MST(X), а v(V) - равным v(X).
Рассмотрим сравнение на равенство
Y = X
(где Y и X являются выражениями). DT(X) и DT(Y) должны иметь общий супертип. Сравнение должно возвращать true, если MST(Y) равно MST(X) и v(Y) равно v(X), иначе - false.
Пусть rx и ry - отношения с общим атрибутом A, и пусть объявленные типы A в rx и ry
- это DT(Ax) и DT(Ay) соответственно. Рассмотрим соединение rx и ry ( обязательно по A, по крайней мере, частично). DT(X) и DT(Y) должны иметь общий супертип и, следовательно, обязательно общий наиболее конкретный супертип, скажем T. Тогда объявленным типом A в результате соединения должен быть тип T.
Аналогичные замечания относятся к объединению, пересечению и разности операций. То есть в каждом случае:
Для каждого типа T должна поддерживаться операция в форме
TREAT_DOWN_AS_T ( X )
(или ее логический эквивалент), где X является выражением. T должен быть подтипом DT(X) и MST(X) должен быть подтипом T. Такие операции обобщенно называются операциями “TREAT DOWN”; их семантика такова:
свой аргумент X (точнее, он должен назначать версию X, для которой DT(X) равно T, но MST(X) и v(X) неизменны). Аргумент X должен быть указан именно как переменная, а не как произвольное выражение.
( Вариант, предполагающий множественное наследование )
Для каждого типа T, должна поддерживаться логическая операция вида
IS_T ( X )
(или ее логический эквивалент), где X - выражение. DT(X) и T
должны иметь общий подтип. Эта операция должна возвращать true, если v(X) принадлежит типу T, и false в противном случае.
Пусть Op - операция только чтения, пусть P - параметр Op, и пусть T - объявленный тип для P. Тогда должно допускаться, чтобы объявленный тип выражения аргумента (и следовательно, тем более, наиболее конкретный тип значения аргумента), соответствующего параметру P в вызове Op, был любым подтипом T' типа T. Другими словами, операция только чтения Op применяется к значениям типа T и поэтому, обязательно, к значениям типа T' – Принцип Наследования Операций (Только Чтения). Из этого следует, что такие операции являются полиморфными, поскольку они применимы к значениям нескольких различным типам – Принцип Полиморфизма Операций (Только Чтения). И далее из этого следует, что везде, где допускается значение типа T, должно также допускаться значение любого собственного подтипа T – Принцип Возможности Замены (Значений).
Для каждой заданной операции Op должны иметься:
Если действительно существует несколько версий Op, то все эти версии фактически должны реализовывать одну и ту же семантику.
Пусть Op - операция обновления, и пусть P - параметр Op, который не является предметом обновления. Тогда Op
должна вести себя как операция только чтения, насколько это относится к P, и, следовательно, все аспекты IM-предписания 16 должны быть применимы.
Пусть Op - операция обновления, пусть P
- параметр Op, который является предметом обновления, и пусть T
является объявленным типом для P. Тогда неясно, должно ли допускаться, чтобы объявленный тип (и, следовательно, тем более, текущий наиболее конкретный тип) аргумента-переменной, соответствующего параметру P в некотором вызове Op, был собственным подтипом типа T (в некоторых случаях это должно допускаться, а в некоторых - нет). Из этого следует, что для каждой такой операции обновления Op и для каждого параметра P операции Op, который является предметом обновления, необходимо явно установить, для каких подтипов объявленного типа T параметра P операция Op должна наследоваться – Принцип Наследования Операций (Обновления). (И если операция обновления Op не наследуется таким образом типом T', она не должна наследоваться и никаким подтипом типа T'.) Таким образом, операции обновления должны быть только условно полиморфными – Принцип Полиморфизма Операций (Обновления). Если Op является операцией обновления, P - параметр Op, который является предметом обновления, и T'
является таким подтипом объявленного типа T
для P, что для T' наследуется Op, то по определению должно быть можно вызывать Op с аргументом-переменной, соответствующим параметру P, когда этот аргумент принадлежит объявленному типу T' – Принцип Возможности Замены (Переменных).
Объединенный тип (union type) - это такой тип T, что не существует значения, которое принадлежит типу T и не принадлежит какому-либо собственному подтипу T (то есть не существует такого значения v, что MST(v) есть T). Фиктивный тип (dummy type) - это объединенный тип, который не имеет никакого объявленного возможного представления (и, следовательно, никакого селектора); должно разрешаться, чтобы данный объединенный тип был фиктивным типом, если и только если этот объединенный тип не имеет никакого регулярного непосредственного супертипа (где регулярный тип - это тип, который не является фиктивным типом). Более того,
по отношению к каждому скалярному типу; по определению он не имеет никакого объявленного возможного представления и никаких собственных подтипов.
Пусть типы T и T' оба являются типами кортежа или оба являются типами отношения с заголовками
{
{
соответственно. Тогда тип T' является подтипом
типа T (или, эквивалентно, тип T является супертипом типа T'), если и только если для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti (или, эквивалентно, тип Ti является супертипом типа Ti').
Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом:
{
Тогда:
a. кортеж t соответствует заголовку H, если и только если t имеет вид
{
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti и vi - значение типа Ti'.
c. отношение r соответствует заголовку H,
если и только если r состоит из заголовка и тела, где:
· Заголовок r имеет вид
{
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti;
· Тело r - это множество кортежей, которые все соответствуют заголовку r.
Пусть все три типа T, T_alpha, и T_omega - это типы кортежей или типы отношений с заголовками
{
{
{
соответственно. Тогда типы T_alpha и T_omega
являются максимальным типом по отношению к типу T и минимальным типом по отношению к типу T соответственно, если и только если для всех i (i
= 1, 2, …, n) тип Ti_alpha является максимальным типом по отношению к типу Ti и Ti_omega является минимальным типом по отношению к типу Ti.
Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом:
{
Тогда:
{
где для всех i (i = 1, 2, …, n) тип Ti' является подтипом типа Ti',
и vi - это значение типа Ti', то наиболее конкретным типом t
является
TUPLE {
где для всех i (i = 1, 2, …, n) тип MSTi является наиболее конкретным типом значения vi.
{
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti
и наиболее конкретным типом значения vi
(отметим, что разные кортежи в теле r
будут в общем случае принадлежать разным наиболее конкретным типам; таким образом, тип Ti' различается для разных кортежей в теле r) – то наиболее конкретным типом r является
RELATION {
где для всех i (i = 1, 2, …, n), тип MSTi является наиболее конкретным общим супертипом этих наиболее конкретных типов Ti', взятых для всех кортежей в теле r.
Пусть переменная (кортежа или отношения) V имеет объявленный тип T, и пусть заголовок T имеет атрибуты A1,A2, …, An. Тогда можно моделировать V как множество именованных упорядоченных триплетов вида
Имя каждой тройки является именем соответствующего атрибута.
DTi является именем объявленного типа атрибута Ai.
MSTi является именем наиболее конкретного типа – называемого также как текущим наиболее конкретным типом – (для) атрибута Ai. (Если V - переменная отношения, то наиболее конкретный тип Ai
определяется как наиболее конкретный общий супертип наиболее конкретных типов m значений в vi – см. объяснение vi
ниже.)
Если V - переменная кортежа, то vi - это значение наиболее конкретного типа MSTi
– текущее значение (для) атрибута Ai. Если V - переменная отношения, то пусть тело текущего значения V состоит из m кортежей; пометим эти кортежи (в некоторой произвольной последовательности) как “tuple 1”, “tuple 2”, … “tuple m”; тогда vi является последовательностью из m значений (не обязательно различных), являющихся значениями Ai из tuple 1, tuple 2, … tuple m
(в таком порядке); отметим, что все эти значения принадлежат типу MSTi.
Обозначения DT(Ai), MST(Ai), v(Ai) используются для ссылок на компоненты DTi, MSTi, vi соответственно атрибута Ai этой модели переменной кортежа или отношения V. Мы также используем обозначения DT(V), MST(V), для ссылки на объявленный тип целиком, текущий наиболее конкретный тип целиком и текущее значение целиком соответственно переменной кортежа или отношения V. Отметим, что фактически MSTi(Ai) подразумевается v(Ai), и MST(V) подразумевается v(V).
Пусть теперь X - выражение кортежей или отношений. Только что введенные обозначения Dti(V), MSTi(V),vi(V) можно очевидным образом расширить для ссылки на объявленный тип Dti(X), текущий наиболее конкретный тип MSTi(X)и текущее значение vi(X) соответственно компонентов Dti, MSTi, vi атрибута Ai
выражения кортежей или отношений X.
для краткости тип) интерпретируются как
Термины домен и тип данных ( для краткости тип) интерпретируются как синонимичные и взаимозаменяемые. В том же самом смысле иногда используется термин объектный класс, но Д&Д не используют этот термин.Д&Д обобщенно называют значения домена скалярными значениями (для краткости скалярами). Тем самым явно допускаются “скалярные” значения произвольной сложности. Например, при определенных обстоятельствах массив стеков списков … и т.д. может рассматриваться как скалярное значение.
Логические различия и логические ошибки, концептуальная целостность
Наиболее важным принципом, которым руководствовались Д&Д на протяжении своей работы над Третьим Манифестом, является следующий: все логические различия являются большими различиями. Основой любой формальной системы является логика. Поэтому во всем, что относится к формальным системам вообще и что касается Манифеста в частности, различия, которые по своей природе являются логическими, очень важны, и на них следует обращать особое внимание. Из этой максимы следует, что все логические ошибки являются большими ошибками.Принцип концептуальной целостности, который Д&Дтакже относят к числу основополагающих, трактуется в том смысле, что с целью поддержания интеграции концепций необходимо поставить некоторые концепции на первое место. Рассматриваемые концепции должны быть тщательно отобраны, их должно быть как можно меньше, они должны быть согласованы и приемлемы по своей природе.
Модель наследования
В Третьем манифесте представлена хорошо проработанная, концептуально согласованная модель наследования, базирующаяся на концепции специализации путем ограничения. Д&Д сначала разрабатывают теорию одиночного наследования для скалярных типов, затем развивают ее для множественного наследования скалярных типов и, наконец, обобщают до случая множественного наследования типов кортежей и ограничений. В этой статье мы не можем полностью (хотя бы кратко) описать модель. Ограничимся изложением предписаний (IM -предписаний, IM от Inherinence Model ).C имволы T и T' используются далее для обозначения пары типов, таких что T' является подтипом T (или, что эквивалентно, T является супертипом для T'). В общем случае эти типы могут быть не только скалярными.
Некоторые ключевые логические различия
Существуют некоторые логические различия, которые имеют отношение ко всему дальнейшему – это различия между (a) моделью и реализацией, (b) значением и переменной, и (c) значением, видом и кодировкой.Различие между моделью и реализацией определяется следующим образом:
Различие между моделью и реализацией в действительности является важным частным случаем различия между логическим и физическим аспектами системы. Во всем Манифесте и во всей книге Д&Д имеют дело с абстрактной моделью, а не с вопросами реализации. (Под “реализацией” понимается реализация СУБД, а не некоторого приложения, работающего под управлением этой системы.)
Второе логическое различие – это различие между значениями
и переменными (под переменной мы понимаем переменную в обычном смысле языка программирования). Используются следующие определения:
Значение – это “индивидуальная константа” (например, индивидуальная константа “3”).113
У значения нет позиции во времени и пространстве. Однако значения могут быть представлены в памяти (посредством некоторой кодировки), и у таких представлений (видов) имеется позиция во времени и пространстве: любое число различных переменных может иметь одно и то же значение одновременно или в разное время. По определению значение невозможно модифицировать.
Переменная – это контейнер вида значения. Переменная имеет позицию во времени и пространстве. Переменные, в отличие от значений, можно модифицировать; т.е. текущее значение данной переменной можно заменить другим значением, возможно, отличным от исходного.
Значения могут быть произвольно сложными; например, значение может быть массивом, стеком, списком, отношением, геометрической точкой и т.д. Аналогичное замечание относятся и к переменным.
Общие принципы
Здесь мы опираемся на материал первых двух глав [20]. Назначение материала состоит в том, чтобы ввести некоторую концептуальную базу для дальнейшего изложения.Неявные преобразования типов препятствовали бы
В языке D следует поддерживать некоторый уровень наследования типов (см. OO-предписания 2 и 3). В соответствии с этим суждением в D не следует поддерживать принуждения (т.е. неявные преобразования типов).Комментарии
Неявные преобразования типов препятствовали бы достижению цели заменяемости; отмеченные параметры вводили бы искусственную и не необходимую степень асимметрии.
Определениям операций следует быть логически отличимыми от определений типов их параметров и/или результатов; эти определения не следует связывать в один узел (хотя селекторы и операции, требуемые в RM-предписании 5 можно рассматривать как исключения по отношению к этому суждению).112
Следует поддерживать генераторы типов “коллекций”, такие как LIST, ARRAY и SET, распространенные в языках с развитыми системами типов.
Для любого генератора типа коллекции С, отличного от RELATION, следует обеспечить операцию преобразования (скажем, C2R) для преобразования значений заданного типа, сгенерированного C, в отношения, и обратную операцию (скажем, R2C) такую, что:
должно быть возможно выполнять проверку
В D должна допускаться проверка типов во время компиляции.Комментарии
В этом предписании имеется в виду, что – насколько это осуществимо – должно быть возможно выполнять проверку на стадии компиляции, чтобы на стадии исполнения не могли происходить какие-либо ошибки типов.
Если в языке D поддерживается наследование типов, то такая поддержка должна подчиняться модели наследования, определенной в Части IV этой книги.108
D должен быть вычислительно полным. То есть в D могут поддерживаться ( но не должны требоваться) вызовы из так называемых “основных программ”, написанных на языках, отличных от D. Аналогично, в D может поддерживаться (но не должно требоваться) использование других языков программирования для реализации определяемых пользователями операций.
Инициация транзакций должны производиться только посредством явного выполнения операции “begin transaction”. Завершение транзакции должно производиться только посредством выполнения операций “commit” или “rollback”; фиксация всегда должна быть явной, а откат может быть неявным (в том и только в том случае, когда транзакция завершается неуспешно не по своей вине). Если транзакция TX
завершается фиксацией (“нормальное завершение”), то изменения, произведенные TX в соответствующей базе данных, должны быть зафиксированы. Если транзакция TX
завершается откатом (“аварийное завершение”), то изменения, произведенные транзакцией TX в соответствующей базе данных, должны быть аннулированы.
В D должны поддерживаться вложенные транзакции, т.е. должна допускаться инициация транзакцией-предком TX транзакции- потомка TX’ до завершения транзакции TX. При этом:
должны взаимодействовать с одной и той же базой данных (что в действительности требуется RM-предписанием 17);
не должна завершаться до завершения TX’; другими словами, TX’ должна полностью содержаться в TX.
Пусть AggOp – агрегатная
операция, такая как SUM. Если аргумент AggOp
является пустым, то:
Категорически отвергается равенство вида
Переменные relvar – это не домены.Комментарии
Категорически отвергается равенство вида “отношение = объектный класс” (более точно, равенство “relvar = объектный класс”)109.
Никакая relvar базы данных не должна содержать атрибут типа pointer (указатель ).110
Комментарии
Отвергается идея “объектных идентификаторов”. Как следствие этого, отвергаются (a ) идея о том, что такие идентификаторы могли бы использоваться в “объектах” для совместного использования “подобъектов”; (b ) идея о том, что пользователи могли бы быть обязаны “разыменовывать” такие идентификаторы (явно или неявно), чтобы получать значения.
Также отвергается идея “идентификаторов кортежей” (как кажется, некоторые авторы отождествляют идентификаторы кортежей и идентификаторы объектов).
Это запрещение не препятствует тому, чтобы объекты вне базы данных обладали идентификаторами, которые являются “каким-либо образом отличными” от самих объектов. Оно не препятствует также появлению таких идентификаторов в базе данных. (Термин “объект” используется здесь в его общем смысле, а не в специализированном смысле объектно-ориентированного подхода.) Поэтому, например, домен имен файлов базовой операционной системы является допустимым доменом.
Основы будущих систем баз данных
В качестве названия этого раздела была выбрана часть названия второго издания книги Дейта и Дарвена “Основы будущих систем баз данных: третий манифест” [20]. Этот выбор названия раздела не случаен, потому что раздел базируется на этой книге – она для него означает примерно то же, что книги [5] и [13] для подразделов 2.2 и 3.2 соответственно.Прежде, чем переходить к основному материалу раздела, кратко представим содержание книги [20]. Прежде всего, заметим, что это второе издание, вышедшее в свет в 2000 г. Первое издание было опубликовано в 1998 г. под названием “Основы объектно/реляционных баз данных” [19]. Вот что пишут Д&Д по поводу изменения названия в предисловии ко второму изданию [20]: “Название первой редакции характеризовало Манифест как “основание объектно/реляционных баз данных”. Хотя эта характеристика была точной, она не была достаточной. Теперь мы считаем Манифест (как, впрочем, было всегда) основанием будущих баз данных вообще – включая, например, базы данных, содержащие темпоральные данные, и базы данных, используемые в связи с World Wide Wed .”
Однако, как кажется, более вероятными причинами для смены названия были следующие обстоятельства:
Сами они используют ( или стремятся использовать) это слово только в неформальном смысле. Но в этом случае неясно, как следует трактовать названием первого издания. Основы чего предлагают авторы?
Конечно, второе издание [20] появилось так скоро после выхода в свет первого издания не только и не столько потому, что авторы решили изменить название. В первом издании была недостаточно доработана часть книги, посвященная наследованию типов. За два года после выхода в свет этого издания Д&Д сумели построить законченную модель наследования, и именно желание представить полный вариант своих предложений побудило авторов к быстрым подготовке и публикации второго издания книги.
Второе издание [20] имеет следующую структуру. Основной текст книги разделен на четыре части: вступление, формальные спецификации, неформальные обсуждения и объяснения, подтипизация и наследование.
Первая часть книги состоит из двух вводных глав, написанных без привлечения каких-либо формализмов. В главе 1 содержится базовая информация, поясняющая некоторые основополагающие идеи, лежащие в основе книги. В частности, обсуждаются ключевые логические различия между понятиями м одели и реализации; значения и переменной; значения, вида и кодировки
значения. Глава 2 состоит из неформального обсуждения двух возможных подходов к ключевому вопросу интеграции объектов и отношений (что соответствует понятию объектного класса в реляционной модели данных?). Демонстрируется, что один из этих подходов является правильным, а другой – ложным.
Вторая часть
книги носит наиболее формальный характер. В главе 3 приводится сам Третий манифест в том виде, как мы изложили его в подразделе 4.1. В главе 3 содержится определение новой реляционной алгебры (“A ”). В главе 4 определяется язык Tutorial D . Этот язык основывается на принципах, заложенных в Манифесте, и на алгебре A . Tutorial D служит основой для примеров в следующих главах книги. Он также позволяет судить о том, что могла бы представлять собой на практике СУБД, поддерживающая идеи Манифеста.
Третья часть
представляет собой реальную сердцевину книги. Она состоит из шести глав, по одной для каждого из шести разделов Манифеста, как он определяется в главе 3. Эта часть, по существу, является сильно расширенным вариантом неформальных комментариев к предписаниям, запретам и очень строгим суждениям Третьего манифеста
Четвертая часть книги играет для подтипизации и наследования ту же роль, что первые три части . Так, глава 12
соответствует первой части (она содержит общее введение в тему ); глава 13 соответствует второй части (она содержит формальные определения); а главы 14, 15 и 16 соответствуют третьей части (они содержат расширенные, но неформальные пояснения и обсуждения этих формальных определений). Точнее, в главе 14
рассматривается только одиночное наследование при наличии скалярных типов; в главе 15 идеи, обсуждаемые в главе 14, расширяются для включения поддержки множественного наследования; в главе 16 в расчет принимаются также типы кортежей и отношений.
В дополнение к перечисленным главам в книге содержится одиннадцать приложений.
В этом подразделе мы остановимся на следующих темах, обсуждаемых в книге [20]:
Первая реализация
Первый коммерчески доступный продукт, основанный на идеях Третьего манифеста, был выпущен около двух лет назад компанией Alphora ( ). Продукт получил название Dataphor .Базовым компонентов Dataphor является Data Access Engine (DAE ), который представляет собой истинную ( т. е. соответствующуютребованиям Третьего манифеста) системуреляционныхбазданных. Полная и точная реализация реляционной модели в DAE обеспечивает следующие возможности:
Полная целостность данных. Полностью поддерживается каждое правило приложения, что обеспечивает, помимо технической согласованности данных, гарантию соответствия деятельности компании установленным требованиям закона.
“Сложные” типы данных. Обеспечивается возможность определения типов данных разработчиками, и эти типы данных равноправны со встроенными типами.
Работа с отсутствующей информации без привлечения неопределенных значений и трехзначной логики.
Обновляемые представления без ограничений, свойственных SQL .
Разработан и реализован язык D 4, обладающий следующими особенностями:
Для выражения запросов используется алгебраический подход.
Запросы, адресуемые к сложным данным, формулируются более точно, чем на языке SQL .
То же касается сложных операций обновления.
Язык обладает вычислительной полнотой.
Язык претендует на то, чтобы стать открытым стандартом, заменяющим SQL .
Не ясно, поддерживается ли в D 4 (и в DAE ) механизм наследования типов. Компания и разработанная ей система очень молоды, и перспективы успеха на рынке более чем неочевидны.
По поводу приведенных примеров следует сделать несколько замечаний:
Объявленный тип каждого аргумента должен быть в точности тем же, что и объявленный тип соответствующего параметра (исключения возможны, если поддерживается наследование типов).
Важное логическое различие имеется между операциями обновления и операциями только чтения. Операции обновления применяются к переменным, а не к значениям. Следовательно, операции только чтения применяются к значениям (в частности, они применимы к значениям, которые являются текущими значениями переменных); операции обновления применяются именно к переменным.
Когда вызывается операция обновления, аргументы, соответствующие параметрам, которые являются предметом обновления (аргументы, соответствующие параметрам, указанным в спецификации UPDATES ), должны быть заданы как переменные, а не как произвольные выражения, и при вызове операции этим переменным потенциально присваиваются значения. Другие аргументы таких вызовов (и все аргументы вызовов операций только чтения) могут быть специфицированы как произвольные выражения.
Аргументы, которые соответствуют параметрам, являющимся предметом обновления, всегда передаются по ссылке, из чего следует, что операции над этими параметрами являются в действительности операциями над соответствующими аргументами (в частности, присваивание значения такому параметру в действительности присваивает значение соответствующему аргументу). Все другие аргументы передаются по значению, и операции над соответствующими параметрами в действительности являются операциями над “фиктивными” (создаваемыми системой) аргументами, которым задаются те же значения, что и подлинным аргументам.
Поскольку вызов скалярной операции только чтения возвращает скалярный результат, такой вызов представляет собой частный случай скалярного выражения.
Он может появиться везде, где может появиться вызов скалярного селектора. Таким образом, посредством вложения вызовов скалярных операций только чтения может быть построено скалярное выражение любой сложности.
Поскольку системе известны объявленные типы всех параметров и всех результатов скалярных операций, система знает, какие скалярные выражения допустимы (т.е. не приводят к возникновению ошибок, связанных с типами). Система знает также тип результата каждого такого допустимого выражения. Такой тип называется объявленным типом скалярного выражения.
Поскольку вызов операции обновления не возвращает результата, такой вызов стоит рассматривать как оператор, а не как выражение. В частности, он не может выступать в качестве аргумента для других вызовов операций.
Как отмечалось ранее, в определении любого скалярного типа должно указываться по крайней мере одно объявленное возможное представление для значений этого скалярного типа (и при таком заданном скалярном типе T и таком возможном представлении PR каждое значение типа T должно быть представимо посредством PR ).118Объявление возможного представления автоматически приводит в действие поддержку соответствующего селектора (и нельзя обеспечить селекторы никаким другим способом). Следовательно, селекторы и возможные представления находятся во взаимно однозначном соответствии друг с другом (параметры селекторов и компоненты возможных представлений находятся также во взаимно однозначном соответствии). Поэтому можно принять соглашение о задании селектору и соответствующему возможному представлению одного и того же имени (хотя они являются логически различными понятиями).
Следует подчеркнуть различия между вызовами селекторов вообще и литералами в частности. Коротко говоря, все литералы являются вызовами селекторов, но не все вызовы селекторов являются литералами. Вызов селектора является литералом тогда и только тогда, когда его аргументы (если они есть) в свою очередь являются литералами. Таким образом, литерал является символом, который обозначает некоторое фиксированное значение, которое определяется на все времена конкретным рассматриваемым символом.
Объявленный тип этого символа ( который является, конечно, частным случаем выражения) также определяется самим.
Вернемся к примеру определяемого пользователем типа POINT , чтобы обсудить вопросы определения
и реализации типов. Повторим в упрощенном виде определение этого типа:
TYPE POINT
POSSREP POINT { X LENGTH, Y LENGTH }
POSSREP POLAR { R LENGTH, THETA ANGLE } ;
В данном примере в определении типаспецифицированы два объявленных возможных представления – POINT и POLAR . Следовательно, будут существовать две соответствующие операции выбора: POINT , которая позволяет пользователю задавать декартовы координаты X и Y как два значения типа LENGTH и возвращает соответствующее значение типа POINT , и POLAR , которая позволяет пользователю задавать полярные координаты R и THETA как значения типов LENGTH и ANGLE соответственно и возвращает соответствующее значение типа POINT .
Предположим, что представление с декартовыми координатами на самом деле является реальным. Тогда в системе будут поддерживаться высоко защищенные операции, не входящие в D , которые раскрывают это реальное представление, и реализатор типа будет использовать эти операции для реализации требуемых селекторов POINT и POLAR . Вот, например, возможная реализация (псевдокод) для селектора POINT :
OPERATOR POINT ( X LENGTH, Y LENGTH ) RETURNS POINT ;
BEGIN ;
VAR P POINT ;
P.X := X ; /* assign to actual representation */
P.Y := Y ; /* assign to actual representation */
RETURN P ;
END ;
END OPERATOR ;
“Высоко защищенные операции, не входящие в D ” представлены в приведенном коде посредством точечной нотации. Селектор POLAR также мог бы быть реализован “вне среды D ” (снова псевдокод):
OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ;
BEGIN ;
VAR P POINT ;
P.X := R * COS ( THETA ) ;
P.Y := R * SIN ( THETA ) ;
RETURN P ;
END ;
END OPERATOR ;
Но селектор POLAR , возможно, менее эффективно мог бы быть реализован в терминах селектора POINT :
OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ;
RETURN POINT ( R * COS ( THETA ), SIN ( THETA ) ) ;
END OPERATOR ;
Из всего этого следует, что реализаторы типа(но не определители типа и, конечно, не пользователи типа) должны на самом деле знать реальные представления.
Пусть PR - это возможное представление скалярного типа T , и пусть у PR имеются компоненты C 1 , C 2 , …, Cn . Определим THE _ C 1 , THE _ C 2 , …, THE _ Cn как семейство операций, таких что для каждогоi (i = 1, 2, …, n ), операция THE _ Ci обладает следующими свойствами:
Ее единственный параметр имеет тип T .
Если ссылка на операцию, появляется в позиции “источника” (в частности, в левой части присвоения), то операция возвращает компонент Ci своего аргумента. (Точнее, она возвращает значение компонента Ci возможного представления PR ( v ) значения своего аргумента v .)
Если ссылка на операцию, появляется в позиции “цели” (в частности, слева от присвоения), то:
Аргумент должен быть явно указан как переменная, а не произвольное выражение.
Ссылка действует как ссылка на псевдопеременную, и это означает, что она реально обозначает компонент Ci этого аргумента, а не только возвращает значение его значение. (Точнее, она обозначает компонент Ci возможного представления PR ( V ) аргумента-переменной V .)
Несколько примеров :
TYPE TEMPERATURE POSSREP CELSIUS { C RATIONAL } ;
VAR TEMP TEMPERATURE ;
VAR CEL RATIONAL ;
CEL := THE_C ( TEMP ) ;
THE_C ( TEMP ) := CEL ;
В первом присваивании температура, измеренная в градусах Цельсия, которая является текущим значением переменной TEMP типа TEMPERATURE , присваивается переменной CEL типа RATIONAL ; во втором – текущее значение переменной CEL типа RATIONAL , рассматриваемое как температура в градусах Цельсия, используется для обновления переменной TEMP типа TEMPERATURE . Операция THE _ C фактически раскрывает возможное представление температуры посредством “градусов Цельсия” как для целей обновления, так и для целей только чтения.
Но это возможное представление не обязательно является реальным представлением; например, температуру можно было бы представлять в градусах Фаренгейта, а не в градусах Цельсия.
Вот немного более сложный пример:
TYPE POINT POSSREP POINT { X LENGTH, Y LENGTH } ;
VAR L LEHGTH ;
VAR P POINT ;
L := THE_X ( P ) ;
THE_X ( P ) := L ;
В первом присваивании переменной L типа LEHGTH присваивается координата X точки, являющейся текущим значением переменной P типа POINT ; во втором – текущее значение переменной L типа LEHGTH используется для обновления координаты X переменной P типа POINT . Операции THE _ X и THE _ Y фактически раскрывают возможное представление точек посредством “Декартовых координат” как для целей обновления, так и для целей только чтения; и снова это возможное представление не обязательно совпадает с реальным представлением.
Заметим теперь, что псевдопеременные THE _ логически необязательны. Рассмотрим второе присваивание в первом примере. Это присваивание, в котором используется псевдопеременная, логически эквивалентно другому, в котором псевдопеременная не используется:
TEMP := CELSIUS ( CEL ) ; /* вызов селектора CELSIUS */
Вот логический эквивалент второго присваивания во втором примере без использования псевдопеременной:
P := POINT ( L, THE_Y ( P ) ) ; /* вызов селектора POINT */
Другими словами, псевдопеременные как таковые не являются строго необходимыми для поддержки обсуждаемой разновидности обновления на уровне компонентов. Однако подход с использованием псевдопеременных интуитивно выглядит более привлекательным, чем альтернативный (для которого первый подходможно рассматривать как сокращенную форму); более того, он также обеспечивает высокую степень устойчивости к изменениям синтаксиса соответствующего селектора.
Заметим также, что по поводу реализации операций раскрытия возможного представления можно сделать замечания, аналогичные тем, которые приводились выше в связи с операциями выбора значений скалярного типа.
В объектной технологии имеется одна
В объектной технологии имеется одна безусловно хорошая идея – определяемые пользователями типы (включая определяемые пользователями операции). Одна идея является вероятно хорошей – наследование типа (хотя не здесь судить, насколько именно хорошей ). Ключевой технической идеей Третьего Манифеста является то, что эти две идеи полностью ортогональны реляционной модели. Чтобы достичь желательной объектной функциональности, не надо абсолютно ничего делать с реляционной моделью.Пользователям требуются истинно реляционные СУБД (“истинно реляционные системы” не означают SQL-ориентированные системы), в которых содержится должная поддержка доменов, и тогда они получат “объектно/реляционные” СУБД, которых добивались. Привлекательность собственно
объектных СУБД (в противоположность “объектно/реляционным” СУБД) можно целиком объяснить частичной неудачей существующих поставщиков SQL-ориентированных систем в части должной поддержки реляционной модели. Но это не является аргументом для отказа от реляционной модели.
это именованное множество скалярных значений.
Скалярный тип данных– для краткости, скалярный тип – это именованное множество скалярных значений. Два скалярных типа одинаковы в том и только в том случае, когда на самом деле являются одним и тем же типом (что подразумевает, в частности, наличие у них одного и того же имени; если типы не одинаковы, их имена должны различаться). Язык D должен обеспечивать пользователям возможности определять собственные скалярные типы (определяемые пользователями скалярные типы); другие скалярные типы должны обеспечиваться системой (встроенные или определяемые системой скалярные типы). Должна иметься возможность уничтожения определенных пользователями скалярных типов. Значениями заданного скалярного типа и переменными, значения которых должны принадлежать данному скалярному типу, можно оперировать только с помощью операций, определенных для этого типа (говорится, что операция “определена для” данного типа T , или “ассоциирована с” ним, если и только если хотя бы один ее параметр объявлен с указанием типа Т – см. RM -предписание 3). Для каждого скалярного типа и каждого объявленного возможного представления его значений (см. RM -предписание 4) в состав этих операций должны входить:
Операция selector, служащая для выборки произвольного значения данного скалярного типа (см. RM-предписание 4);
Набор операций для раскрытия рассматриваемого возможного представления (см. RM-предписание 5).
В состав определяемых системой скалярных типов должен входить тип truth value (с ровно двумя значениями, true и false). Для этого типа должны прямо или косвенно определяться и поддерживаться все четыре унарные и 16 бинарных логических операций.99
Все скалярные значения должны быть типизированы, т.е., по крайней мере, концептуально должны позволять идентифицировать (уникальный) тип, которому они принадлежат.
Скалярная операция
- это операция, которая возвращает скалярное значение или обновляет скалярную переменную. Язык D должен обеспечивать для пользователей возможности определения собственных скалярных операций (определяемых пользователями скалярных операций); другие такие операции (встроенные или определяемые системой скалярные операции) должны обеспечиваться системой. В общем случае должно быть возможно уничтожать определенные пользователями скалярные операции (хотя операции, требуемые RM-предписаниями 5, 8 и 21, слегка нарушают это предписание в том отношении, что их можно уничтожить только посредствам уничтожения ассоциированного типа, и то же верно для операций выборки). Кроме того:
Определение скалярной операции должно включать спецификацию типа каждого параметра этой операции, объявленный тип параметра. Если операция Op
имеет параметр P объявленного типа T, то аргумент A, соответствующий P, в каждом вызове Op должен иметь тот же тип T.
Каждая скалярная операция представляет из себя либо операцию обновления, либо операцию только чтения. Скалярная операция обновления – это такая скалярная операция, по меньшей мере один аргумент которой должен быть задан путем указания скалярной переменной, а не произвольного скалярного выражения, и вызов операции приводит к присваиванию значений таким аргументам (по крайней мере, потенциально); параметры, соответствующие подобным аргументам, называются подлежащими обновлению. Скалярная операция только чтения – это скалярная операция, не являющаяся скалярной операцией обновления.
Вызов скалярной операции только чтения должен возвращать (скалярный) результат. Вызов скалярной операции обновления – нет.
В определении скалярной операции только чтения должна содержаться спецификация типа результата этой операции, объявленного типа этого результата (в просторечии, объявление типа собственно операции).
В определение скалярной операции обновления должно указываться, какие аргументы являются подлежащими изменению.
Пусть T – скалярный тип, а v – вид ( в некотором контексте) некоторого значения этого типа. Тогда по определению у v имеется в точности одно реальное представление и одно или более возможных представлений (по крайней мере, одно, так как, очевидно, одно возможное представление всегда существует и совпадает с реальным представлением). Реальные представления, связанные с типом T, должны определяться средствами некоторого языка определения структуры хранения и не должны быть видимы в языке D (см. RM-предписание 6). По крайней мере одно возможное представление (не обязательно совпадающее с реальным представлением), связанное с типом T, должно быть объявлено как часть определения T
и, следовательно, должно быть видимо в языке D. Для каждого объявленного возможного представления PR типа T должна автоматически обеспечиваться операция selector S со следующими свойствами:
Для определенности предположим, что компоненты PR (см. RM-предписание 5) и параметры S представлены в виде упорядоченных списков. Тогда эти два списка должны содержать одно и то же число элементов, скажем n, и объявленные типы i-тых элементов списков (i = 1, 2, ..., n) должны быть одинаковы.
Каждое значение типа T
должно производиться путем некоторого вызова S.
Пусть некоторое объявленное возможное представление PR для скалярного типа T определено в терминах компонентов C1, C2, ..., Cn (у каждого компонента имеются имя и объявленный тип). Пусть v
– значение типа T, а PR(v) обозначает соответствующее возможное представление. Тогда PR(v)
должно быть раскрываемым – иначе говоря, должен автоматически обеспечиваться набор операций только чтения и обновления, такой что:
= 1, 2, ..., n) можно “выбрать” (т.е. прочитать значение) компонента Ci из PR(v).
= 1, 2, ..., n) можно обновить V таким образом, что если значениями V до и после обновления являются v и v’
соответственно, то возможные представления PR(v) и PR(v’) отличаются самое большее в их компонентах Ci.
Такой набор операций должен обеспечиваться для каждого возможного представления, объявленного в определении T.
Должен поддерживаться генератор типов TUPLE .102 То есть при наличии некоторого заголовка кортежа H (см. RM-предписание 9) должна быть возможность использовать генерируемый тип TUPLE {H} как основу определения (или, в случае значений, выборки):
Генерируемый тип TUPLE {H} называется типом кортежей; имя этого типа – TUPLE {H}. Терминология степени, атрибутов и заголовков, вводимая в RM-предписании 9, должна применяться, с необходимыми изменениями,к этому типу кортежей, а также к значениям и переменным этого типа (см. RM -предписание 12). Типы кортежей TUPLE {H1} и TUPLE {H2} одинаковы в том и только в том случае, когда H1 = H2. В состав применимых операций должны входить аналоги операций реляционной алгебры RENAME, project, EXTEND и JOIN (см. RM-предписание 18), а также операции присваивания кортежей (см. RM-предписание 21) и сравнения кортежей (RM-предписание 22); кроме того, в состав операций должны входить (a) операция выборки кортежей (RM-предписание 9), (b) операция извлечения из указанного кортежа значения указанного атрибута (степень этого кортежа должна равняться единице – см. RM-предписание 9) и (c) операции “вкладывания” и “выкладывания” кортежей.
Должен поддерживаться генератор типов RELATION. То есть при наличии некоторого заголовка отношения H
(см. RM-предписание 10) должна иметься возможность использования генерируемого типа RELATION {H} как основы для определения (или, в случае значений, для выборки):
Генерируемый тип RELATION {H} называется типом отношения, и имя этого типа – RELATION {H}. Терминология степени, атрибутов и заголовков, вводимая в RM-предписании 10, должна применяться, с необходимыми изменениями,к этому типу отношения, а также к значениям и переменным этого типа (см. RM -предписание 13). Типы отношения RELATION {H1} и RELATION {H2} одинаковы в том и только в том случае, когда H1 = H2. В состав применимых операций должны входить операции реляционной алгебры (см. RM-предписание 18), а также операции реляционного присваивания (см. RM-предписание 21) и реляционного сравнения (RM-предписание 22); кроме того, в состав операций должны входить (a) операция выборки отношений (RM-предписание 10), (b) операция извлечения единственного кортежа из указанного отношения мощности один (RM-предписание 10), и (c) операции “вкладывания” и “выкладывания” отношений.
Комментарии
С точки зрения любого отношения, которое включает атрибут, определенный на таком домене, “скалярные” значения в этом домене (как и значения всех доменов) являются все еще инкапсулированными. (Аналогичное замечание относится также к RM -предписанию 6.) В Третьем манифесте не поддерживаются в явном виде отношения в форме NF 2 (“NF в квадрате”103), введение которых влечет существенные расширения классической реляционной алгебры.
Для каждого типа должна поддерживаться операция сравнения по равенству, “=”. Пусть выражения X1 и X2
имеют значения v1 и v2 соответственно, причем v 1 и v 2 принадлежат одному и тому же типу T . Тогда операция X1 = X2 вырабатывает значение true в том и только в том случае, если v1 и v2 в действительности являются одним и тем же элементом T (то есть тогда и только тогда, когда X1 и X2 имеют одно и то же значение). Кроме того, пусть Op – это операция с параметром P объявленного типа T. Тогда для всех таких операций Op, если значением сравнения X1 = X2 является true , последствия двух (успешных) вызовов Op, которые отличаются только тем, что в одном из них аргументом, соответствующим P, является X1, а в другом – X2, должны быть неразличимы. Или, по-другому, если существует такая операция Op, что последствия двух (успешных) вызовов Op, которые отличаются только тем, что в одном из них аргументом, соответствующим P, является X1, а в другом – X2, различимы, то значением сравнения X1 = X2 должно быть false.
Значение кортежа t (или для краткости кортеж) – это множество упорядоченных триплетов вида , где:
A – имя атрибута кортежа t. Никакие два различных триплета в t не должны содержать одно и то же имя атрибута;
T – имя типа атрибута A кортежа t.
v – значение типа T, называемое значением атрибута A кортежа t.
Мощность множества триплетов в t, или число атрибутов t называется степенью t. Множество упорядоченных пар , получающихся путем удаления компонента v (значения) из каждого триплета, является заголовком t. Кортеж t называется соответствующим
этому заголовку (принадлежит к соответствующему типу кортежа – см. RM-предписание 6). Степенью
заголовка является степень кортежа, а атрибутами и соответствующими типами заголовка являются атрибуты и соответствующие типы кортежа t. При заданном заголовке H должна быть доступна операция selector для выборки произвольного кортежа, соответствующего H.
Значение отношения
r (для краткости – отношение) состоит из заголовка и тела, где:
Заголовком r является заголовок кортежа H как определяется в RM-предписании 9. Отношение r называется соответствующим этому заголовку (принадлежит к соответствующему типу отношения – см. RM-предписание 7), а степенью r является степень этого заголовка. Атрибутами и соответствующими типами r являются атрибуты и соответствующие типы H.
Тело r – это множество B кортежей, каждый из которых имеет заголовок H; мощность тела называется мощностью
r.
При заданном заголовке отношения H должна быть доступна операция selector для выборки произвольного отношения, соответствующего H.
Комментарии
Каждый кортеж в R содержит в точности одно значениеv для каждого атрибута A в H . Иными словами, R находится в первой нормальной форме, 1NF .
Проводится строгое различие между отношениями как таковыми и переменными-отношениями (см. РМ-предписание13).104
Скалярная переменная типа T – это переменная, допустимыми значениями которой являются скаляры указанного скалярного типа T, объявленного типа этой переменной. Язык D
должен обеспечивать для пользователей возможности определения скалярных переменных. При определении скалярной переменной должна производиться инициализация переменной некоторым значениям – явно указанным в операции определения переменной или не указанным явно, а определенным в реализации.
Переменная кортежа типа TUPLE {H} – это переменная, допустимыми значениями которой являются кортежи, соответствующие указанному заголовку кортежа H. Объявленный тип этой переменной кортежа есть TUPLE {H}. Атрибутами переменной кортежа являются атрибуты H, соответствующими типами – объявленные типы этих атрибутов, степенью переменной кортежа является степень H. Язык D должны обеспечивать для пользователей возможности определения переменных кортежей. При определении переменной кортежа должна производиться инициализация переменной некоторым значением – явно указанным в операции определения переменной или не указанным явно, а определенным в реализации.
Переменная отношения (relation variable , для краткости – relvar) типа RELATION {H} – это переменная, допустимыми значениями которой являются отношения, соответствующие указанному заголовку отношения H. Объявленный тип relvar есть RELATION {H}. Атрибутами relvar являются атрибуты H, соответствующими типами – объявленные типы этих атрибутов, степенью relvar является степень H. Язык D должен обеспечивать для пользователей средства определения и уничтожения переменных relvar базы данных (для тех relvar, которые принадлежат базе данных, а не приложению – см. RM-предписание 16). Язык D должен также поддерживать возможности определения relvar на уровне приложений.
Переменные r elvar базы данных могут быть реальными или виртуальными. Виртуальная relvar – это relvar базы данных, значением которой в любой момент времени является результат вычисления некоторого реляционного выражения, указываемого при определении этой relvar. Реальная relvar – это relvar базы данных, которая не является виртуальной. При определении реальной relvar должна производиться ее инициализация пустым отношением (т.е. отношением мощности нуль).
Комментарии
Реальные и виртуальные relvar соответствуют тому, что обычно называют “базовыми отношениями” и “обновляемыми представлениями” соответственно. Однако Д&Д полагают, что обновляемые представления составляют значительно более широкую категорию представлений, чем это принято считать при использовании традиционных подходов.
По определению у каждой relvar имеется по меньшей мере один возможный ключ. По меньшей мере один такой ключ должен быть определен при определении relvar, и не должна иметься возможность ликвидировать все возможные ключи данной relvar (кроме как ликвидировав саму relvar).
База данных – это именованный контейнер relvar; содержимое базы данных в любой момент времени – это набор relvar базы данных. Операции, необходимые для определения и ликвидации баз данных, не должны являться частью языка D (другими словами, определение и ликвидация баз данных должна производиться “за пределами среды D”).
Каждая транзакция
должна взаимодействовать в точности с одной базой данных. Однако разные транзакции должны иметь возможность взаимодействия с разными базами данных, и разные базы данных не обязательно должны быть разъединенными. Кроме того, транзакции должны иметь возможность определять новые и уничтожать существующие relvar внутри соответствующей базы данных (RM-предписание 13).
В языке D должны поддерживаться обычные операции реляционной алгебры (или их некоторые логические эквиваленты). Конкретно, должны прямо или косвенно поддерживаться, по меньшей мере, операции RENAME, restrict (WHERE), project, EXTEND, JOIN, UNION, INTERSECT, MINUS, (обобщенная) DIVIDEBY PER и (обобщенная) SUMMIRIZE PER. Все такие операции должны выражаться без чрезмерного многословия. В языке D
должен также обязательно поддерживаться механизм вывода типов отношения, благодаря чему заголовок результата вычисления произвольного реляционного выражения должен быть правильно определенным и известным как системе, так и пользователю (RM-предписание 7).105
Комментарии
Оборот “без чрезмерного многословия” предполагает наряду с другими вещами, что:
Должны быть в равной мере легко выразимы кванторы всеобщности и существования. Например, если D включает специальную операцию для реляционной проекции отношения, то он должен также включать и специальный оператор для общей формы реляционного деления.
Должны быть также в равной мере легко выразимы проекция на указанные атрибуты и проекция на все атрибуты, кроме указанных.
Имена relvar и вызовы селектора отношений должны быть допустимыми реляционными выражениями. В реляционных выражениях должна допускаться рекурсия.106
В D должны поддерживаться возможности для определения и уничтожения операций только чтения со значениями-отношениями. Отношение, являющееся результатом вызова такой операции, должно определяться некоторым реляционным выражением, указываемым при определении операции. В этом выражении должно допускаться наличие параметров; наличие таких параметров должно допускаться в любом месте, где допускаются вызовы селекторов (операций выборки). Вызовы таких операций внутри реляционных выражений должны допускаться в любом месте, где разрешаются вызовы селекторов отношений.
В D должно допускаться:
присваивание
(значения) скалярного выражения скалярной переменной;
присваивание
(значения) кортежного выражения переменной кортежа;
присваивание
(значения) реляционного выражения relvar.
В каждом случае типы источника и цели должны совпадать. В дополнение к этому в языке D должна поддерживаться множественная форма операции присваивания, в которой несколько отдельных операций присваивания выполняются параллельно как одна логическая операции.
В D должны поддерживаться некоторые операции сравнения, а именно:
Во всех случаях, кроме “Î ”, операнды должны быть одного типа, а в случае “Î ” кортеж и отношение должны иметь одинаковые заголовки.
Выражение, при вычислении которого вырабатывается истинностное значение, называется логическим выражением (также называемое истинностным, условным или булевским выражением). Ограничением целостности является логическое выражение, которое: a) именовано; b) является замкнутой WFF (Well Formed Formula – правильно построенной формулой) реляционного исчисления или ее логическим эквивалентом; с) при вычислении должно вырабатывать значение true. Язык D должен обеспечивать возможности для определения и уничтожения ограничений целостности. Такие ограничения должны классифицироваться на ограничения типа, атрибута, relvar и базы данных, и в D
должен поддерживаться механизм вывода
ограничений, ассоциированный с этой схемой классификации (насколько это осуществимо).
Для каждой relvar имеется соответствующий предикат relvar, и для каждой базы данных имеется соответствующий предикат базы данных. Все такие предикаты должны удовлетворяться в границах оператора.107
Комментарии
Предикат отношения представляет собой, по существу, конъюнкцию всех ограничений целостности, которые налагаются на соответствующую relvar , а предикат базы данных – это конъюнкция всех ограничений целостности, которые налагаются на соответствующую dbvar . Это исключительно важный момент – предикаты, а не имена представляют семантику базы данных.
Утверждение о том, что предикаты отношений должны удовлетворяться на границах операторов, означает в точности то, что никакая реляционная операция присваивания не должна оставлять какую-либо relvar в состоянии, в котором нарушается ее предикат отношения.
Из этого предписания, кроме того, следует, что должно быть невозможно обновлять “обновляемые представления” (т.е. виртуальные relvar ) таким образом, чтобы нарушалось определение этого представления. Иными словами, “обновляемые представления” всегда должны быть предметов того, что называется в SQL CASCADED CHECK OPTION [23].
Каждая база данных должна включать набор relvar, составляющих каталог этой базы данных. Должна существовать возможность производить присваивания для relvar каталога.
Комментарии
Из этого предписания следует, что каталог должен представлять собой нечто, что обычно называется “самоописанием”.
атрибуты которого различаются своими порядковыми
D не должен включать концепцию “отношения”, атрибуты которого различаются своими порядковыми позициями. Для каждого отношения r, выражаемого средствами D, атрибуты r должны различаться своими именами.Комментарии
Из этого запрета следует, что не допускаются никакие анонимные столбцы, такие как в операторе SQL SELECT X + Y FROM T , и никакие дубликаты имен столбцов, как в операторах SQL SELECT X , X FROM T и SELECT T 1.X , T 2.X FROM T 1, T 2.
D не должен включать концепцию “отношения”, в котором кортежи различаются своими порядковыми позициями. Для каждого отношения r, выражаемого средствами D, кортежи r должны различаться своими значениями.
Комментарии
Из этого запрета вовсе не следует, что такое упорядочение не может быть введено, например, для целей представления. Скорее, из него следует, что в результате введения такого упорядочения отношение конвертируется в нечто, что не является отношением (возможно, в последовательность или упорядоченный список).
D не должен включать концепцию “отношения”, содержащего два различных кортежа t1 и t2
таких, что результатом сравнения кортежей “t 1 = t 2” является true . Отсюда следует, что (как уже утверждалось в RM -запрете 2) кортежи r должны различаться своими значениями.
Комментарии
Другими словами, “строки-дубликаты” являются незаконными абсолютно, категорически и однозначно незаконными.
D не должен включать концепцию отношения, в котором некоторый “кортеж” включает некоторый “атрибут”, не имеющий значения (соответствующего типа).
Комментарии
Другими словами – никаких неопределенных значений и никакой многозначной логики!
В D должно учитываться, что отношения без атрибутов приемлемы и интересны, и что то же относится к возможным ключам без компонентов.
D не должен содержать конструкции, которые связаны с “физическим” уровнем системы, уровнем “хранения”, “внутренним” уровнем или образованы под логическим влиянием этих уровней.
В D не должны поддерживаться покортежные операции над relvar или отношениями.
Комментарии
Операции INSERT , UPDATE и DELETE , если они обеспечиваются, вставляют, модифицируют или удаляют соответственно всегда множество кортежей. Множество, состоящее из одного кортежа, является всего лишь частным случаем.
Покортежная выборка (аналогичная той, которая выполняется через курсор посредством SQL -оператора FETCH ) – хотя она запрещается и вообще считается бесполезной – фактически может выполняться, если это желательно, путем конвертирования этого отношения в упорядоченный список кортежей и итерирования этого списка.
Категорически запрещается покортежное обновление (аналогичное операторам SQL UPDATE и DELETE , выполняемым через курсор).
D не должен включать какую-либо специальную поддержку “составных”, или “сложных” атрибутов, поскольку подобной функциональности можно достичь, если это желательно, более понятным образом на основе уже предписанной поддержки типов.
D не должен включать операции, “отвергающие ограничения доменов”, поскольку такие операции являются нештатными и необязательными.
RM-запреты
Внимательный читатель заметит, что многие из запретов в этом разделе являются логическими следствиями RM -предписаний. Однако в связи с теми ошибками, которые были, к сожалению, допущены в SQL , Д&Д ощущают, что в целях пояснения необходимо описать некоторые из этих следствий.Система типов
Здесь мы кратко обсудим основные положения [20], связанные с построением системы типов, собрав воедино развернутые комментарии Д&Д к разным предписаниям, запретам и очень строгие суждения Третьего манифеста.Скалярные типы
Термин типохватывает и скалярные и не скалярные типы. Между скалярными и не скалярными типами имеется принципиальное различие. Скалярные типы вне зависимости от уровня сложности их реальных представлений – не содержат компонентов, видимых для пользователя.115 Напротив, не скалярные типы содержат видимые для пользователя компоненты; в частности, типы кортежей и отношений не являются скалярными и содержат наборы видимых для пользователя атрибутов.
Значения некоторого скалярного типа обобщенно называются скалярными значениями (для краткости, скалярами). Аналогично, переменные, значения которых ограничиваются скалярами, обобщенно называются скалярными переменными. Реальное представление таких значений и переменных может быть сколь угодно сложным.
Скалярные типы могут определяться пользователями либо быть системно-определенными (“встроенными”). Требуется, чтобы поддерживался хотя бы один встроенный скалярный тип – тип истинностного значения. Для определенности предполагается, что для этого типа поддерживаются операции NOT , AND и OR и литералы TRUE и FALSE . Для удобства считается, что поддерживаются также встроенные скалярные типы INTEGER , RATIONAL (Д&Д предпочитают использовать этот термин вместо REAL ) и CHAR с соответствующими операциями и литералами.
Вот несколько примеров определений пользовательских скалярных типов (используется синтаксис Tutorial D , который в данном случае не требует пояснений).
TYPE S# POSSREP { CHAR } ;
TYPE QTY POSSREP { INTEGER CONSTRAINT QTY > 0 } ;
Здесь у типа S # имеется только одно объявленное возможное представление (“POSSREP ”), обладающее именем S # по умолчанию.116У этого возможного представления имеется ровно один компонент, имя которого по умолчанию совпадает с именем возможного представления, т.е. опять S # . Поскольку этот компонент определяется как принадлежащий типу CHAR , и не указано какое-либо дополнительное ограничение для типа S # , множество допустимых значений этого типа является множеством всех значений, которые можно представить в виде символьных строк.
Тип QTY определяется аналогичным образом, но для него указано дополнительное ограничение – значения этого типа должны быть положительными.
Вот несколько более сложных примеров определения скалярных типов:
TYPE LENGHT POSSREP { L RATIONAL } ;
TYPE POINT
POSSREP POINT { X LENGHT, Y LENGHT
CONSTRAINT … } ;
POSSREP POLAR { R LENGHT, THETA ANGLE
CONSTRAINT … } ;
TYPE POLYGON
POSSREP { VERTICES
RELATION { V# INTEGER, VERTEX POINT
CONSTRAINT … } ;
Определение типаLENGTH аналогично ранее приведенным определениям типов за исключением того, что единственному компоненту возможного представления этого типа задано явное имя L . ТипPOINT (“точка”) отличается от предыдущих примеров тем, что у него есть два различных объявленных возможных представления: первое –POINT (у этого возможного представления то же имя, что и у типа), с компонентами (Декартовыми координатами) X и Y , и второе – POLAR с компонентами (полярными координатами)R и THETA . Только в тех случаях, когда заданный тип имеет два или более объявленных возможных представлений, необходимо давать таким возможным представлениям явные имена. ТипELLIPSE (“эллипс”) отличается от предыдущих примеров тем, что его объявленное возможное представление основано не на встроенных, а на определенных пользователем типахLENGTH и POINT . Наконец, типPOLYGON (“многоугольник”) отличается от предыдущих примеров тем, что единственный компонент его объявленного возможного представления VERTICES принимает значения-отношения. То есть многоугольник представлялся бы отношением, содержащим по одному кортежу для каждой вершины этого многоугольника; этот кортеж содержал бы номер вершины (значение типаINTEGER ) вместе с самой соответствующей вершиной (значение типа POINT ).
Следует подчеркнуть, что операция определения типа реально не создает соответствующего множества значений. Концептуально, это множество значений уже существует и всегда будет существовать.
Все, что делает операция “определения типа”, заключается в введении имени, посредством которого можно ссылаться на это множество значений. Из RM -предписания 2 следует, что любое значение всегда относится к одному и только одному типу (если не поддерживается наследование). Побочным (но важным) следствием является то, что пересечение множеств значений любых двух различных типов всегда пусто (опять же при отсутствии наследования).
Скалярная операция – это операция, возвращающая скалярное значение или обновляющая скалярную переменную. 117 Как и скалярные типы, скалярные операции могут определяться либо пользователями, либо системой (“встраиваться”). Встроенные операции определяются только в связи со встроенными типами. Предполагается, что для встроенных скалярных типов BOOLEAN , INTEGER , RATIONAL и CHAR поддерживается естественный для этих типов набор операций, причем имена некоторых операций перегружены. Определяемые пользователями операции можно определять как для встроенных типов, так и для определяемых пользователями.
Факт существования операции с заданным именем не препятствует возможности перегрузки – то есть определения другой операции с тем же именем, но с другими объявленными типами параметров и (возможно) результатов, и следовательно, по крайней мере, частично отличной семантикой. Можно было бы даже не только перегрузить, но и переопределить существующую операцию посредством определения другой операции с тем же именем и теми же объявленными типами параметров и результатов, но с другой семантикой. По очевидным соображениям, мы рекомендуем, чтобы это средство использовалось со всеми возможными предосторожностями.
Вот пример определяемой пользователем скалярной операции, работающей со встроенным типом:
OPERATOR ABS ( N RATIONAL ) RETURNS RATIONAL ;
RETURN CASE
WHEN N ³ 0.0 THEN +N
WHEN N < 0.0 THEN –N
END CASE ;
END OPERATOR ;
Операция ABS определяется с единственным параметром N объявленного типа RATIONAL и возвращает результат того же объявленного типа.
Это операция только чтения, что означает, что ни при каком вызове функция не пытается обновлять свой собственный аргумент.
Вот другой пример определяемой пользователем скалярной операции только чтения, которая работает с некоторыми определяемыми пользователем типами:
OPERATOR DIST ( P1 POINT, P2 POINT ) RETURNS LENGTH ;
RETURN WITH THE_X ( P1 ) AS X1 ,
THE_X ( P2 ) AS X2 ,
THE_Y ( P1 ) AS Y1 ,
THE_Y ( P2 ) AS Y2 ,
SORT ( ( X1 - X2 ) ** 2 + ( Y1 - Y2 ) ** 2 ) ) ;
END OPERATOR ;
Эта операция, DIST (“расстояние”) определяется с двумя параметров P 1 и P 2 объявленного типа POINT , и возвращает результат объявленного типа LENGTH . Операции THE _ X и THE _ Y используются для получения координат X и Y двух рассматриваемых точек, затем эти координаты используются для получения требуемого расстояния. WITH позволяет ввести сокращения для некоторых выражений.
Для определенности принимается, что аргументы вызовов операций задаются в позиционной нотации, т.е. в данном вызове i -й аргумент в списке аргументов соответствует i -му параметру в списке параметров определения операции.
Вот пример операции обновления:
OPERATOR REFLECT ( P POINT ) UPDATES P ;
BEGIN ;
THE_X ( P ) := THE_X ( P ) ;
THE_Y ( P ) := THE_Y ( P ) ;
RETURN ;
END OPERATOR ;
Операция REFLECT фактически перемещает точку с декартовыми координатами (x ,y ) в центрально-симметричную точку (- x ,- y ). Операция определяется с одним параметром P объявленного типа POINT и при вызове должным образом обновляет аргумент, соответствующий этому параметру. Как в предыдущем примере, операции THE _ X и THE _ Y используются для “чтения” координат X и Y заданной точки; псевдопеременныеTHE _ X и THE _ Y используются для обновления этих координат. Вызов REFLECT не возвращает результата; такой вызов не имеет значения и не является скалярным выражением. Поэтому вызов должен выполняться посредством явного оператора CALL (или некоторого его логического эквивалента).
Типы данных и объектные классы
Чтобы иметь возможность детально обсуждать соотношение между объектной и реляционной технологиями, необходимо разобраться в том, какая концепция в реляционном мире является двойником концепции объектного класса в объектном мире.114Этот вопрос исключительно важен, поскольку объектный класс является фундаментальной концепцией объектного мира, и все остальные объектные понятия в большей или меньшей степени зависят от этой концепции. В качестве ответа на поставленный выше вопрос возможны два ответа: (a ) концепции объектного класса соответствует концепция домена; (b ) концепции объектного класса соответствует концепция отношения (вернее, переменной отношения, relvar ). Д&Д доказывают, что верен только первый ответ. При этом в качестве аксиомы принимается то, что требуется оставаться в классической реляционной среде.
Для начала требуется навести должный порядок в реляционной терминологии. Как следует из классических определений реляционной модели данных, каждое отношение состоит из двух частей, заголовка и тела, где заголовок – это множество пар имя-столбца:имя-домена,
Предлагается следующий способ понимания природы отношений: Для заданного отношения R
заголовок R обозначает некоторый предикат (истинностную функцию), а каждая строка тела R – это некоторое истинное высказывание, получаемое из предиката путем подстановки некоторых значений доменов вместо заменителей или параметров этого предиката (“инстанциация предиката”). Для примера рассмотрим отношение MMQ (“ведомость материалов”) (рис. 3.1).
| MAJOR_P# : P# | MINOR_P# : P# | QTY : QTY |
| P1 | P2 | 5 |
| P1 | P2 | 3 |
| P2 | P3 | 2 |
| P2 | P4 | 7 |
| P3 | P5 | 4 |
| P 4 | P 6 | 8 |
Рис. 3.1. Пример отношения ведомости материалов MMQ (в заголовке показаны имена атрибутов и доменов)
Заголовку отношения MMQ соответствует “деталь MAJOR _ P # содержит QTY деталей MINOR _ P # ”. Следующие высказывания являются истинными: “деталь P 1 содержит 5 деталей P 2 ” (получено подстановкой значений доменов P 1 , 5 и P 2 ); “деталь P 1 содержит 3 детали P 3” (получено подстановкой доменных значений P1 , 3 и P3 ) и т.д.
Другими словами, домены состоят из вещей, о которых мы говорим; отношения состоят из истин, которые мы изрекаем по поводу этих вещей.
Из этого следует, что ( a ) необходимы и домены, и отношения (без доменов не о чем говорить, без отношений нельзя ничего сказать); ( b ) домены и отношения – это не одно и то же; домены и отношения достаточны, равно как и необходимы; с логической точки зрения больше ничего не требуется.
Когда люди говорят об отношениях, они очень часто имеют в виду переменные отношений, а не сами
отношения. В действительности это частный случай логического различия между значениями и переменными. Например, значение данного отношения (множество строк) не меняется во времени, а значение переменной этого отношения меняется. Замечая, что подобно отношению и в отличие от переменной отношения значение данного домена (множество скаляров) также не меняется во времени, можно придти к ложному заключению, что домены и отношения являются вещами одного и того же вида. И наконец, смешение понятий собственно отношений и переменных отношений, приводит к тому (еще большему) заблуждению, что домены и переменные отношений – это одно и то же. Для достижения предельной ясности Д&Д вводят явный термин relvar
как сокращенную форму от relation variable (переменная отношения) и высказываются в терминах relvars, а не отношений, когда имеются в виду действительно переменные отношения.
Теперь можно обсудить то соотношение понятий, которое Д&Д считают правильным – концепция домена соответствует концепции объектного класса. Обычно считается, что домен – это всего лишь концептуальный пул значений, из которого берутся реальные значения столбцов отношений. Такое понимание является удовлетворительным только до поры до времени. В действительности, домен – это то же самое, что тип данных – определенный в системе или определенный пользователем тип. Поэтому эти термины являются взаимозаменяемыми. С понятием типа данных ассоциируется понятие операций, которые допускается применять к значениям этого типа (со значениями типа можно работать только посредством применения операций, определенных для этого типа).
Различаются собственно тип (или домен) и внутреннее представление,или физическая кодировка значений этого типа внутри системы. Например, номера деталей могли бы быть представлены внутренним образом как строки символов, но отсюда не следует, что можно производить операции с номерами деталей как со строками символов. Операции, определяемые для данного типа, зависят от предполагаемого смысла или семантики этого типа, а не от способа представления значений типа в системе. Внутренние представления значений типа должны быть скрыты от пользователя. Подобная строгая типизация в понимании Д&Д означает, что (a) у каждого значения имеется тип и (b) при попытке выполнения любой операции система проверяет, что операнды имеют типы, допустимые для этой операции.
В реляционной модели нет ничего, для чего требовалось бы ограничить типы данных только простыми формами. Единственным требованием является то, что значениями домена можно манипулировать только посредством определенных для него операций; внутреннее представление должно быть скрыто. Другими словами, вопрос о том, какие поддерживаются типы данных, ортогонален вопросу поддержки реляционной модели.
Итак, в реляционном мире домен – это тип данных, определяемый системой или пользователем, значениями которого можно манипулировать только с помощью определенных для него операций (и внутреннее представление которого может быть произвольно сложным, но скрытым от пользователя). Если обратиться к объектному миру, выясняется, что самое фундаментальное среди всех понятий, объектный класс, это тип данных, определенный системой или пользователем, значениями которого можно манипулировать исключительно посредством операторов, определенных для этого типа (и внутреннее представление которого может быть сколь угодно сложным, но скрытым от пользователя). Другими словами, домены и объектные классы – это одно и то же; это обеспечивает ключ к интеграции двух технологий, и именно эта позиция отстаивается в Третьем Манифесте.
Уравнивание объектного класса с relvar является серьезной логической ошибкой.По мнению Д&Д истоки этой ошибки кроятся в синтаксической близости определений класса и переменной отношения. Принципиальное различие понятий заключается в том, что relvar – это переменная, а класс – это тип. (Переменная отношения и домен - это не одно и то же.) Это уже показывает ошибочность уравнивания объектного класса с relvar . Более подробный анализ позволяет придти к выводу, что принятие второго вида уравнивания понятий подрывает концептуальную целостность реляционной модели.
Типы кортежей и отношений
Кортежные типы и типы отношений являются генерируемыми типами, получаемыми путем применения генераторов типа TUPLE и RELATION соответственно. Вот пример использования кортежного типа:VAR ADDR TUPLE { STREET CHAR,
CITY CHAR,
STATE CHAR,
ZIP CHAR } ;
Здесь определяется кортежная переменная ADDR типа
TUPLE { STREET CHAR, CITY CHAR, STATE CHAR, ZIP CHAR }
Это пример генерируемого (кортежного) типа. Каждая из комбинаций “имя : тип” является атрибутом этого кортежного типа, и множество всех таких атрибутов является заголовком кортежного типа. Мощность этого множества называется степенью кортежного типа. Кортежная переменная ADDR имеет те же самые атрибуты, заголовок и степень, и то же касается всех возможных значений этой переменной.
Умышленно не поддерживается отдельная операция “определения типа кортежа”. Одним из оснований для такого решения является то, что иначе потребовалось бы вводить имя кортежного типа (помимо уже существующего имени TUPLE {…}). Такие дополнительные имена усложнили бы другие аспекты предлагаемого Д&Д подхода, например, решения вопроса о том, когда два типа совпадают.119
По этим соображениям предписывается, чтобы кортежные типыиспользовались “в виде подстановки”, как часть операции, которая определяет кортежную переменную отдельно.
Для кортежных типов требуется поддержка “операций, аналогичных операциям RENAME , project , EXTEND и JOIN из реляционной алгебры”. Вот несколько примеров, не требующих специальных пояснений (в последнем примере присутствует вызов селектора кортежей
– фактически, кортежный литерал):
ADDR RENAME ZIP AS POSTCODE /* переименование атрибута кортежа */
ADDR RENAME PREFIX ' ST ' AS ' G ' /* то же самое, префиксный вариант */
ADDR { STATE , ZIP } /* проекция кортежа */
EXTEND ADDR ADD NAME ('Clark Kent') AS NAME /* расширение кортежа */
ADDR JOIN /* соединение кортежей */
TUPPLE { NAME NAME ('Clark Kent') , COUNTRY 'USA' }
Вот пример присваивания кортежей:
ADDR := TUPLE {STREET 'One Jacob Way' ,
CITY 'Reading' ,
STATE 'Massachusetts' ,
ZIP '01870' } ;
Выражение справа от знака присваивания является другим примером вызова селектора кортежей (конечно, это всего лишь кортежный литерал). Переменная кортежа, указанная в левой части кортежного присваивания, и кортеж, обозначенный кортежным выражением в правой части, должны быть одного и того же кортежного типа, т.е. они должны иметь совпадающие имена атрибутов, и соответствующие атрибуты должны быть в свою очередь одного и того же типа.
Следующий пример иллюстрирует обязательную операцию экстракции атрибута, которая выделяет значение указанного атрибута из указанного кортежа:
VAR STATE_VAR CHAR ;
STATE_VAR := STATE FROM ADDR ;
Явно допускается, чтобы кортежи (и отношения) включали атрибуты, значениями которых были бы кортежи. Операции, которые применяются к этим кортежным значениям, это в точности те же операции языка D , которые применяются к кортежным значениям вообще. Вотпример:
VAR NADDR1 TUPLE { NAME NAME,
ADDR TUPLE { STREET CHAR,
CITY CHAR,
STATE CHAR,
ZIP CHAR } } ;
Важное преимущество схемы именования типов кортежей, предписанной в Манифесте, состоит в том, что она облегчает задачу вывода типа результата произвольного кортежного выражения. Например, рассмотрим следующее кортежное выражение (проекцию кортежа):
NADDR2 { NAME, ZIP }
Это конкретное выражение вычисляет кортеж, который порождается из текущего значения NADDR2 путем “проецирования на все, кроме” атрибутовSTREET , CITY и STATE . И кортежный тип этого порожденного кортежа есть в точности
TUPLE { NAME NAME, ZIP CHAR }
Рассмотрим следующие кортежные типы:
TUPLE { NAME NAME, ADDR TUPLE { STREET CHAR, CITY CHAR,
STATE CHAR, ZIP CHAR } }
TUPLE { NAME NAME, STREET CHAR, CITY CHAR,
STATE CHAR, ZIP CHAR }
Будем называть эти два типа TT 1 и TT 2 соответственно. Пусть теперь NADDR 1 и NADDR 2 являются переменными кортежа типов TT 1 и TT 2 , соответственно. Тогда:
NADDR2 WRAP { STREET, CITY, STATE, ZIP } AS ADDR
принимает текущее значение NADDR 2 и “обволакивает” компоненты STREET , CITY , STATE и ZIP этого значения, производя единственный компонент ADDR с кортежным значением. Результат выражения принадлежит, таким образом, типу TT 1 , и тогда (например) допустимо такое присвоение:
NADDR1 := NADDR2 WRAP { STREET, CITY, STATE, ZIP } AS ADDR ;
NADDR1 UNWRAP ADDR
принимает текущее значение NADDR1 и “разворачивает” компонент ADDR (с кортежным значением) этого значения, производя четыре скалярных компонента STREET , CITY , STATE и ZIP . Результат выражения принадлежит, таким образом, типу TT 2 , и тогда допустимо (например) такое присваивание:
NADDR2 := NADDR1 UNWRAP ADDR ;
Все, что говорилось выше по поводу кортежных типов, с небольшими коррективами применимо к типам отношений, и мы не будем повторяться. Остановимся только на двух дополнительных операциях – GROUP и UNGROUP . Рассмотрим следующие типы отношения:
RELATION { S# S#, PQ RELATION { P# P#, QTY QTY } … }
RELATION { S# S#, P# P#, QTY QTY }
Назовем эти два типа отношения RT 1 и RT 2 соответственно. Пусть теперь SPQ 1 и SPQ 2 – это relvar типов RT 1 и RT 2 соответственно. Тогда:
SPQ2 GROUP { P#, QTY } AS PQ
(которое можно было бы прочитать как “сгруппировать SPQ 2 по S # ”, гдеS # –единственный атрибут SPQ 2 , не упомянутый в спецификации GROUP ) вырабатывает отношение, определяемое следующим образом. Во-первых, заголовок выглядит следующим образом:
{ S # S #, PQ RELATION { P # P #, QTY QTY } }
Во-вторых, тело включает ровно по одному кортежу для каждого уникального значения S # в SPQ 2 (и не содержит никаких других кортежей). Каждый кортеж этого тела состоит из соответствующего значения S # (скажем, s ) и значения PQ (скажем, pq ), получаемого следующим образом:
Во-первых, каждый кортеж SPQ 2 заменяется на кортеж (скажем, x ), в котором компоненты P # и QTY обернуты в компонент (скажем, y ) с кортежными значениями.
Компоненты y всех таких кортежей x , у которых значение S # равно s , “группируются” в отношение pq , и тем самым генерируется результирующий кортеж со значением S #, равным s , и значением PQ , равным pq
Таким образом, общий результат относится к типу RT1, и поэтому (например) допустимо следующее присваивание:
SPQ1 := SPQ2 GROUP { P#, QTY } AS PQ ;
Выражение
SPQ 1 UNGROUP PQ
производит отношение, определяемое следующим образом. Во-первых, заголовок выглядит следующим образом:
{ S# S#, P# P#, QTY QTY }
Во-вторых, тело содержит в точности по одному кортежу для каждой комбинации кортежа в SPQ 1 и кортежа в значенииPQ внутри этого кортежа SPQ 1 (и не содержит никаких других кортежей). Каждый кортеж в этом теле состоит из соответствующего значения S # (скажем, s ) и значений P # и QTY (скажем, p и q ), получаемых следующим образом:
Во-первых, каждый кортеж SPQ 1 заменяется на множество кортежей, по одному такому кортежу (скажем, x ) для каждого кортежа в значении PQ кортежа SPQ 1 . Каждый такой кортеж x содержит компонент S # , равный компоненту S # из соответствующего кортежа SPQ 1 , и компонент с кортежным значением (скажем, y ), равный некоторому кортежу из компонента PQ того же кортежа SPQ 1 .
Компоненты y каждого кортежа x , в котором значение S # равняется s , разворачиваются в отдельные компоненты P # и QTY (скажем, p и q ), и тем самым генерируется результирующий кортеж со значением S # , равным s , значением P # , равным p , и значением QTY , равным q .
Таким образом, окончательный результат относится к типу RT 2, и поэтому допустимо следующее присваивание:
SPQ2 := SPQ1 UNGROUP PQ ;
Третий манифест: назад к реляционному будущему
В марте 1995 г. была впервые официально опубликована статья Хью Дарвена и Кристофера Дейта, названная авторами “Третьим манифестом” [3]. Прежде, чем перейти к сути Третьего манифеста, немного поговорим про его авторов.Крис Дейт начал свою карьеру в компании IBM , где, естественно, специализировался в области технологии баз данных. С конца 70-х годов активно занимается писательской деятельности. В 1983 г. Крис Дейт покинул IBM и с тех пор является независимым консультантом. Основным трудом К. Дейта является учебная монография “Введение в системы баз данных”. В 2003 г. вышло в свет уже восьмое издание этой книги. Каждое издание книги существенно отличается предыдущих изданий, но не снижает их собственную значимость. На русском языке опубликованы три издания “Введения в системы баз данных” – 2- e издание [24], 6-е издание [25] и 7-е издание [26]. Дейт также написал и издал серию книг, посвященным конкретным системам: DB 2 [14], SQL / DS и Sybase . В 1997 г. была издана книга [23], написанная при участии Хью Дарвена и являющаяся одним из лучших руководств по стандарту SQL :1992. К. Дейт пишет много статей, которые печатались, главным образом, в журнале Database Programming and Design . Когда этот журнал прекратил свое существование, Дейт некоторое время публиковался в журнале Intelligent Enterprise , в последние годы публикует свои статьи на сайте Фабиана Паскаля (см. [15]). Подборки статей Дейта, а теперь еще и Дарвена издаются в сборниках серии Selected Writings [16]. С 1995 г. К. Дейт (вместе с Хью Дарвеном) развивает и пропагандирует идеи Третьего манифеста.
Хью Дарвен всю жизнь (с 1967 г.) работает в отделении компании IBM в Великобритании. Одной из его профессиональных обязанностей является участие в комитете по стандартизации языка SQL . Дарвен начал сотрудничать с Дейтом в конце 80-х, участвуя в подборе статей для сборников избранных статей. Хью Дарвен принимал участие в написании руководства по стандарту SQL :1992 [23]. Полноправным соавтором Дейта Дарвен стал в 1998 г., когда вышло первое издание книги, посвященной Третьему манифесту.
Итак, в 1998 году вышло первое издание книги Дейта в соавторстве с Хью Дарвеном “Foundation for Object/Relational Databases: The Third Manifesto” [19]. Комментированный пересказ первых двух глав этой книги опубликован в журнале “Открытые системы” [17]. В 2000 году было выпущено второе издание книги под названием “ Foundation for Future Database Systems: The Third Manifesto ” [20]. Это издание подготовлено к публикации на русском языке [21], но к моменту написания этих строк еще не вышло в свет. В 2002 г. появилась еще одна новая книга Дейта и Дарвена (к компании которых присоединился Никос Лоренцос) [18]. В этой книге идеи Третьего манифеста применяются к технологии темпоральных баз данных.
Чтобы плавно подойти к предпосылкам и истокам Третьего манифеста, проследим эволюцию взглядов Криса Дейта.92 Вспомним, что Дейт начинал свою производственную деятельность в компании IBM именно в то время, когда активно развивалась теория реляционных баз данных, и предпринимались первые попытки реализации реляционных СУБД. С одной стороны, Дейт воспитывался на чисто реляционных идеях Эдгарда Кодда [3.2], а с другой стороны участвовал в создании коммерческой СУБД SQL / DS , где эти идеи (как он впоследствии осознал) уже начинали искажаться.
В своих первых книгах, например, в [14] и [24], Крис Дейт еще вполне лояльно относился к коммерческим реляционным СУБД и языку SQL . Но уже в 1984 г. он написал и издал статью “Критика языка баз данных SQL ” [22], в которой обсуждались недостатки используемого в то время варианта языка. В шестом издании своей основной книги [25] (1995 г.) Дейт очень резко говорит об SQL (имея в виду стандарт SQL :1992), а в книге [22] грамотное и лаконичное описание стандарта языка соседствует с очень язвительными (хотя и весьма остроумными) замечаниями. Заметим, что замечания Дейта по поводу недостатков языка SQL всегда носили очень конструктивный характер – он стремился не только показать отклонения SQL от принципов реляционной модели данных, но и продемонстрировать, что желаемую функциональность можно было получить без потребности в этих отклонениях.
В этой ситуации публикации Первого и Второго манифестов [1 – 2]не могли быть спокойно восприняты Дейтом. Действительно, в Первом манифесте по существупредлагалосьреволюционным образом отказаться от “устаревшей” реляционной модели данных и перейти к применению парадигмы объектной ориентированности в области управления данными. Естественно, это противоречило убеждению Дейта о совершенстве и универсальности реляционной модели. Во Втором манифесте лукаво говорилось о необходимости сохранения поддержки реляционной модели в системах баз данных следующего поколения, но в действительности речь шла о поддержке SQL . Естественно, это противоречило убеждению Дейта об ущербности и ограниченности языка SQL .
Конечно, можно было выбрать привычный для Дейта способ реакции – опубликовать серию статей с критикой обоих манифестов. Но это было бы не конструктивно, поскольку не предлагался бы какой-либо “правильный” (с точки зрения Дейта) путь дальнейшего развития технологии баз данных. Так родился Третий манифест, представляющий собой набор достаточно точно сформулированных конструктивных предложений, следование которым может (по мнению Дейта) привести к созданию СУБД следующего поколения, удовлетворяющим современным потребностям и базирующимся на чистой реляционной модели93.
В документе [3] почти совсем отсутствует критика предыдущих манифестов (и чего бы то ни было другого). Зато критика с избытком представлена в книгах [18 – 19]. Обсудим, по какой причине Хью Дарвену и Крису Дейту94 понадобилось писать специальную книгу, посвященную Третьему манифесту. Все дело в том, что положение Д&Д коренным образом отличается от положения авторов первых двух манифестов. Эти авторы сочиняли свои манифесты, опираясь на существующие коммерческие (или хотя бы исследовательские) реализации. Цель каждого из манифестов состояла в действительности в том, чтобы показать правильность направления, по которому движется соответствующая область индустрии систем управления данными. За спиной Д&Д не было ничего, кроме классической реляционной теории.
Поэтому, чтобы Третий манифест не выглядел голословным, необходимо было произвести его детальную проработку.
Естественно, два человека (талантливых и очень образованных человека), ни один из которых не имеет практического опыта проектирования и разработки СУБД, никак не могут довести свои идеи не только до стадии реализации, но даже до стадии технического проектирования. Поэтому в [18 – 19] Д&Д постоянно подчеркивают, что их обсуждения находятся на модельном, а не на реализационном уровне. Более того, Д&Д выражают желание, чтобы их книга рассматривалась бы как современное изложение реляционной модели данных. Однако, по мнению автора данной статьи, во многих местах [18 – 19] материал носит существенно более конкретный характер, чем это принято при описании абстрактных моделей.
Мы начнем этот раздел с изложения Третьего манифеста в том виде, в котором он приведен в [19].95
Во втором разделе мы кратко обсудим наиболее интересные идеи [19], относящиеся к системе типов и модели наследования. Кроме того, мы приведем критику Д&Д и собственные комментарии по поводу первых двух манифестов и связанных с ними работ. Наконец, в третьем разделе будет рассмотрена первая попытка создания коммерческой СУБД, основанной на идеях Третьего манифеста.
Третий манифест
Статья [3] представляет собой манифест, касающийся будущего систем управления данными и СУБД. Д&Д следуют традициям первых двух манифестов [1 – 2] и надеются, что данный манифест сможет их заменить. Это обосновывает выбор названия. В [1] презрительно отвергается реляционная модель данных, игнорируется ее важность и значимость. Вместе с этим, как считают Д&Д, эта работа терпит неудачу в попытке определить какую-либо четкую линию. В [2] вежливо отдается должное реляционной модели, но в погоне за идеалами этой модели не упоминается и не подчеркивается безнадежность продолжения следования извращению этой модели, воплощенному в SQL . В отличие от этого, Д&Д твердо убеждены, что любая попытка двигаться вперед, чтобы выдержать испытание временем, должна сопровождаться полным и недвусмысленным отказом от SQL . При этом должно уделяться некоторое внимание вопросу, что следует делать с наследством SQL .Основы будущих систем баз данных не способен обеспечить язык SQL . Д&Д полагают, что любые такие основы должны корениться в реляционной модели данных, впервые представленной миру Э.Ф. Коддом в 1969 г. [4]
Д&Д в полной мере осознают желательность поддержки некоторых активно обсуждавшихся возможностей, в частности, тех возможностей, которые считаются присущими объектной ориентации. Однако они полагают, что эти возможности ортогональны реляционной модели. И поэтому реляционная модель не нуждается в каком-либо расширении, в какой-либо коррекции, и самое главное, в каких-либо извращениях, чтобы можно было связать эти возможности с некоторым языком баз данных, способным представлять искомые основы. Предположим, что такой язык существует и называется D”.96
В Третьем манифесте язык D является предметом формулируемых предписаний и запретов.97
Некоторые предписания проистекают из существа реляционной модели, и Д&Д называют их RM -предписаниями. Предписания, не связанные с реляционной моделью, называются OO -предписаниями (от Other Orthogonal ). Аналогичным образом разделяются запреты.
RM -предписания и RM -запреты абсолютны и не могут быть предметом компромисса. К сожалению, этого нельзя сказать про OO -предписания и OO -запреты, поскольку ко времени написания статьи не существовало общепринятой модели, на которой они могли бы базироваться.98
Д&Д полагают, что OO -предписания могут внести значительный вклад в областях определяемых пользователями типов данных и наследования. Д&Д предпринимают усилия, чтобы привести в этих областях собственные определения, и предупреждают читателя, что наследование порождает ряд вопросов, на которые в доступной литературе отсутствуют ответы. Поэтому в этой области предписания необходимо могут быть только предварительными. Наряду с предписаниями и запретами, Третий манифест включает некоторые весьма строгие суждения, которые также подразделяются на RM - и OO -категории.
Базы данных: Разработка - Управление - Excel
- Базы данных
- Разработка баз данных
- СУБД и базы данных
- Управление базами данных
- Классика баз данных
- Софт для создания базы данных
- SQL
- Access
- FoxProо
- Расширенная оптимизация подзапросов в Oracle
- Informix
- Линтер
- Postgres
- СУБД DB2
- InterBase
- Excel
- Таблицы Excel
- Справка Excel
- Программирование в Excel
- Деньги в Excel
- Задачи Excel