Объектные субд. Простая объектная субд

Связь между записью-владельцем и записью-членом также имеет вид 1:N.

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

  • деревья (a) и (b), показанные на рис. 4.2 , заменяются одной сетевой структурой, в которой запись СОТРУДНИК входит в два групповых отношения;
  • для отображения типа M:N вводится запись СОТРУДНИК_КОНТРАКТ, которая не имеет полей и служит только для связи записей КОНТРАКТ и СОТРУДНИК, (см. рис. 4.3). Отметим, что в этой записи может храниться и полезная информация, например, доля данного сотрудника в общем вознаграждении по данному контракту.


Рис. 4.3.

Каждый экземпляр группового отношения характеризуется следующими признаками:

Способ упорядочения подчиненных записей:

  • произвольный,
  • хронологический /очередь/,
  • обратный хронологический /стек/,
  • сортированный.

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

Режим включения подчиненных записей:

  • автоматический - невозможно занести в БД запись без того, чтобы она была сразу же закреплена за неким владельцем;
  • ручной - позволяет запомнить в БД подчиненную запись и не включать ее немедленно в экземпляр группового отношения. Эта операция позже инициируется пользователем.

Режим исключения.

Принято выделять три класса членства подчиненных записей в групповых отношениях:

  • Фиксированное. Подчиненная запись жестко связана с записью владельцем и ее можно исключить из группового отношения только удалив. При удалении записи -владельца все подчиненные записи автоматически тоже удаляются. В рассмотренном выше примере фиксированное членство предполагает групповое отношение "ЗАКЛЮЧАЕТ" между записями "КОНТРАКТ" и "ЗАКАЗЧИК", поскольку контракт не может существовать без заказчика.
  • Обязательное. Допускается переключение подчиненной записи на другого владельца, но невозможно ее существование без владельца. Для удаления записи-владельца необходимо, чтобы она не имела подчиненных записей с обязательным членством. Таким отношением связаны записи "СОТРУДНИК" и "ОТДЕЛ". Если отдел расформировывается, все его сотрудники должны быть либо переведены в другие отделы, либо уволены.
  • Необязательное. Можно исключить запись из группового отношения, но сохранить ее в базе данных не прикрепляя к другому владельцу. При удалении записи -владельца ее подчиненные записи - необязательные члены сохраняются в базе, не участвуя более в групповом отношении такого типа. Примером такого группового отношения может служить "ВЫПОЛНЯЕТ" между "СОТРУДНИКИ" и "КОНТРАКТ", поскольку в организации могут существовать работники, чья деятельность не связана с выполнением каких-либо договорных обязательств перед заказчиками.

Операции над данными в сетевой модели БД

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

Ограничения целостности

Как и в иерархической модели обеспечивается только поддержание целостности по ссылкам (владелец отношения - член отношения).

Достоинства и недостатки ранних СУБД

Достоинства ранних СУБД:

  • развитые средства управления данными во внешней памяти на низком уровне;
  • возможность построения вручную эффективных прикладных систем;
  • возможность экономии памяти за счет разделения подобъектов (в сетевых системах)

Недостатки ранних СУБД:

  • сложность использования;
  • высокий уровень требований к знаниям о физической организации БД;
  • зависимость прикладных систем от физической организации БД;
  • перегруженность логики прикладных систем деталями организации доступа к БД.

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

Объектно-ориентированные СУБД

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

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

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

Структура

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

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

Целостность данных

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

  • автоматическое поддержание отношений наследования возможность объявить некоторые поля данных и методы объекта как "скрытые", не видимые для других объектов; такие поля и методы используются только методами самого объекта создание процедур контроля целостности внутри объекта

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

К сожалению, в объектно-ориентированном программировании отсутствуют общие средства манипулирования данными, такие как реляционная алгебра или реляционное счисление. Работа с данными ведется с помощью одного из объектно-ориентированных языков программирования общего назначения, обычно это SmallTalk, C++ или Java.

Подведем теперь некоторые итоги

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

В то же время, ОО - модели присущ и ряд недостатков :

  • отсутствуют мощные непроцедурные средства извлечения объектов из базы. Все запросы приходится писать на процедурных языках, проблема их оптимизации возлагается на программиста;
  • вместо чисто декларативных ограничений целостности (типа явного объявления первичных и внешних ключей реляционных таблиц с помощью ключевых слов PRIMARY KEY и REFERENCES ) или полудекларативных триггеров для обеспечения внутренней целостности приходится писать процедурный код.

Очевидно, что оба эти недостатка связаны с отсутствием развитых средств манипулирования данными. Эта задача решается двумя способами - расширение ОО-языков в сторону управления данными (стандарт ODMG), либо добавление объектных свойств в реляционные СУБД (SQL-3, а также так называемые объектно-реляционных СУБД).

Объектно-ориентированные базы данных – базы данных, в которых информация представлена в виде объектов, как в объектно-ориентированных языках программирования.

Применять или не применять объектно-ориентированные системы управления базами данных (ООСУБД) в реальных проектах сегодня? В каких случаях их применять, а в каких нет?

Вот преимущества использования ООСУБД:

  • Отсутствует проблема несоответствия модели данных в приложении и БД (impedance mismatch). Все данные сохраняются в БД в том же виде, что и в модели приложения.
  • Не требуется отдельно поддерживать модель данных на стороне СУБД.
  • Все объекты на уровне источника данных строго типизированы. Больше никаких строковых имен колонок! Рефакторинг объектно-ориентированной базы данных и работающего с ней кода теперь автоматизированный, а не однообразный и скучный процесс.
Интересно? Тогда стоит попробовать!

В статье описано все, что требуется для начала работы с ООСУБД db4o .

Установка db4o

На сегодняшний день db4o – одна из самых популярных объектно-ориентированных систем управления базами данных.

Для начала скачиваем дистрибутив последней версии с сайта db4o (есть версии для Java, .NET 2.0, 3.5). На момент написания статьи последняя версия – 7.9. В дистрибутив также входит Object Manager Enterprise (OME) – полезный плагин для IDE (Eclipse, Visual Studio), который позволяет работать с базой данных автономно. В последнюю продуктивную поставку (на данный момент - 7.4) OME не входит, поэтому для ознакомления c ООСУБД рекомендуется версия 7.9.

После установки db4o в соответствующем месте можно найти отличный tutorial, входящий в комплект. Именно к нему я рекомендую обратиться после прочтения данной статьи, если сама тема покажется вам интересной.

Отмечаю, что все ПО для работы с db4o и сама СУБД бесплатны для некоммерческого использования.

Cоединение с БД

Для проведения экспериментов над db4o создаем в нашей IDE проект любого типа, например, консольное приложение и добавляем ссылки на сборки (пакеты) db4o: Db4objects.Db4o.dll и Db4objects.Db4o.Linq.dll (если требуется).

Чтобы выполнять какие-либо действия над объектной базой в приложении, первым делом необходимо получить объект типа IObjectContainer . Это фасад к базе данных: через него выполняются запросы к БД на выборку, сохранение, добавление и удаление данных.

Способ получения объекта зависит от типа соединения с базой данных.

Самый простой способ – база данных размещается в локальном файле, к которому приложение получает доступ напрямую. Делается это так:

// получаем доступ к файлу БД
IObjectContainer db = Db4oFactory.OpenFile(filename);
try
{
// работаем с ООБД
}
finally
{
// закрываем файл, освобождаем ресурсы
db.Close();
}

Файл базы данных в этом случае открывается в эксклюзивном режиме и, следовательно, возникают трудности при реализации многопользовательских приложений. Однако такое решение отлично подходит для однопользовательских stand-alone приложений, которые имеют сложную модель данных и которым необходимо сохранять эти данные между запусками приложения. Пример, САПР-приложения.

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

// создаем сервер
IObjectServer server = Db4oFactory.OpenServer(filename, 0);
try
{
// подключаем клиентов
IObjectContainer client = server.OpenClient();
IObjectContainer client2 = server.OpenClient();

// работаем с ООБД через экземпляры IObjectContainer

Client.Close();
client2.Close();
}
finally
{
// закрываем файл, освобождаем ресурсы сервера
server.Close();
}

* This source code was highlighted with Source Code Highlighter .


В данном случае при создании сервера все равно приходится указывать файл базы данных. Это необходимо делать для всех типов подключения к БД - привязка к файлу остается всегда (один файл - одна БД). Кстати, такой файл создается автоматически по первому требованию, если не был создан до этого.

Второй параметр функции OpenServer – номер порта, равный 0, означает, что сервер будет доступен только локальным клиентам, создаваемым с помощью server.OpenClient() .

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

И последний вариант – расширение предыдущего для случая удаленных клиентов.

// создаем сервер
IObjectServer server = Db4oFactory.OpenServer(filename, serverPort);
server.GrantAccess(serverUser, serverPassword);

try
{
IObjectContainer client = Db4oFactory.OpenClient("localhost" , serverPort,
serverUser, serverPassword);
// работаем с ООБД
client.Close();
}
finally
{
server.Close();
}

* This source code was highlighted with Source Code Highlighter .


Этот вариант отличается от предыдущего следующим.
  • Указывается реальное значение порта, который будет прослушивать сервер (используется TCP/IP) при вызове OpenServer .
  • Указываются авторизационные данные для доступа к БД.
  • Клиент создается с использованием Db4oFactory.OpenClient и, таким образом, это может происходить не только в другом потоке, но и совершенно в другом приложении, запущенном на удаленной машине.
Итак, мы рассмотрели все три способа подключения к базе данных и научились получать объект типа IObjectContainer . Посмотрим теперь, как работать с данными, используя этот объект.

Работа с данными

Пусть где-то в нашем приложении объявлен класс User с полями Login , Password и Age , а db – это объект типа IObjectContainer (тот, что мы получили в прошлом разделе).

Сохранение объекта (INSERT)

User user1 = new User("Vasya", "123456", 25);
db.Store(user1);

* This source code was highlighted with Source Code Highlighter .


Это всё! Не требуется заранее или вручную задавать, какие объекты мы можем сохранять в БД, структуру этих объектов или что-либо ещё. При сохранении первого объекта ООСУБД сделает всю работу за нас.

Запросы к данным (SELECT)

Существует несколько способов выполнить запрос к данным, сохраненным в базе данных.

Применение естественных запросов (Native Queries, NQ) – гибкий, мощный и удобный метод выполнения запросов над данными в ООБД.

IList result = db.Query(usr => usr.Age >= 18
&& usr.Login.StartsWith("V"));

* This source code was highlighted with Source Code Highlighter .


Здесь делается запрос к объектам класса User , причем всё, что только можно, в данном примере строго типизировано. Объекты фильтруются таким образом, чтобы удовлетворять условию: возраст пользователя больше или равен 18 и имя пользователя начинается с заглавной буквы «V». Вместо лямбда-выражения функции Query можно передавать делегаты или объекты типа Predicate . Predicate - интерфейс, содержащий единственную функцию Match , принимающую параметр типа T и возвращающую bool . Query вернет те объекты, для которых Match возвращает true .

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

IEnumerable result = from User usr in db
where usr.Age >= 18 && usr.Login.StartsWith("V" )
select usr;

* This source code was highlighted with Source Code Highlighter .


Запрос опять же строго типизирован и легко поддается рефакторингу.

Существуют и другие методы выполнения запросов, кроме NQ и LINQ.

  • Запросы по образцу (query by example). Самый простой, но недостаточно мощный способ. Выборка данных осуществляется на основе сопоставления с заранее подготовленным экземпляром объекта - образцом. Результат-выборка не является строго типизированной. Сложно представить ситуации, когда этот метод может оказаться полезным.
  • SODA. Низкоуровневый язык запросов, с которым работает db4o. Запросы, использующие синтаксис SODA, не безопасны с точки зрения типов, не строго типизированы, занимают много места, но зато максимально гибки и позволяют отточить производительность приложения там, где это требуется.

Обновление объектов (UPDATE)

Перед тем как обновить объект, извлечем его из БД, затем изменим его и сохраним обратно.
User usr = db.Query(usr => usr.Login == "Vasya" );
usr.SetPassword("111111" );
db.Store(usr);

* This source code was highlighted with Source Code Highlighter .

Удаление объектов (DELETE)

Удаление объектов происходит аналогично:
User usr = db.Query(usr => usr.Login == "Vasya" );
db.Delete(usr);

* This source code was highlighted with Source Code Highlighter .

Составные объекты

До этого момента мы рассматривали, как работать с достаточно простыми объектами User , которые содержали только поля элементарных типов (string и int ). Однако объекты могут быть составными и ссылаться на другие объекты. Например, в классе User может быть объявлено поле friends (друзья пользователя):
public class User
{
// ...
IList friends = new List ();
}

* This source code was highlighted with Source Code Highlighter .


Все операции с таким классом производятся также, как и раньше – составное поле корректно сохраняется в БД, однако есть некоторые особенности.

Допустим, мы пытаемся загрузить из БД объект одного конкретного пользователя (User ), как это делалось в прошлом разделе. Если загружен сам пользователь, то должны загрузиться и его друзья, дальше – друзья его друзей, и так далее. Это может закончиться тем, что придется загрузить в память все объекты User или даже, если у User есть ссылки на объекты других типов, всю базу данных целиком. Естественно, такой эффект нежелателен. Поэтому, по умолчанию загружаются только сами объекты выборки и объекты, на которые они ссылаются, до 5-го уровня вложенности включительно. Для некоторых ситуаций это много, для других – мало. Существует способ настроить этот параметр, называемый глубиной активации (activation depth ).

// глубина активации глобально для всех классов
db.Ext().Configure().ActivationDepth(2);

// глубина активации для класса User
db.Ext().Configure().ObjectClass(typeof (User)).MinimumActivationDepth(3);
db.Ext().Configure().ObjectClass(typeof (User)).MaximumActivationDepth(4);

// каскадная активация для объектов User (нет ограничения на глубину)
db.Ext().Configure().ObjectClass(typeof (User)).CascadeOnActivate(true );

* This source code was highlighted with Source Code Highlighter .


Здесь приведены примеры, устанавливающие глубину активации как для всех сразу, так и для отдельного класса. Функция Ext() возвращает расширенный объект IExtObjectContainer для доступа к продвинутым функциям вроде настроек конфигурации базы данных. Это сделано для удобства, чтобы не засорять основной интерфейс IObjectContainer .

В случае, когда запрос уже отработал, но каких-либо данных не хватает, то есть не все нужные данные были активированы (загружены в память), можно использовать метод Activate , применительно к отдельному хранимому объекту:

// первый параметр – активируемый объект, второй – глубина активации
db.Activate(usr, 5);

* This source code was highlighted with Source Code Highlighter .


Во многом похожая проблема возникает при сохранении составных объектов. По умолчанию сохраняются только поля самого объекта, но не объектов, на которые он ссылается. То есть, глубина обновления (update depth ) по умолчанию равна 1. Изменить её можно следующим образом:
// глубина обновления глобально для всех классов
db.Ext().Configure().UpdateDepth(2);

// глубина обновления для класса User
db.Ext().Configure().ObjectClass(typeof (User)).UpdateDepth(3);

// каскадное обновление для объектов User (нет ограничений на вложенность)
db.Ext().Configure().ObjectClass(typeof (User)).CascadeOnUpdate(true );

* This source code was highlighted with Source Code Highlighter .


В случае удаления объекта, по умолчанию также не происходит каскадного удаления: объекты, на которые ссылался удаленный объект, остаются. Настраивать поведение СУБД в случае удаления объектов можно следующим образом:
// каскадное удаление (нет ограничений на вложенность)
db.Ext().Configure().ObjectClass(typeof (User)).CascadeOnDelete(true );

* This source code was highlighted with Source Code Highlighter .


Понятия «глубины удаления» не предусмотрено.

Транзакции

Каждый раз, когда открывается контейнер (IObjectContainer ), неявным образом создается контекст транзакции. При выполнении операции Close автоматически происходит commit текущей транзакции.

Для более гибкого управления транзакциями в интерфейсе IObjectContainer присутствуют два метода:

  • Commit() . Явное завершение транзакции (commit) с записью всех изменений в БД.
  • Rollback() . Откат транзакции – изменения произошедшие с момента открытия транзакции (контейнера) не будут зафиксированы в БД.
Уровень изоляции транзакций, принятый в db4o - read committed .

Заключение

Цель данной статьи - показать, что имеется очень мощная альтернатива существующим подходам к разработке с использованием реляционных СУБД. Сам по себе подход, использующий объектные базы данных, очень современен – это СУБД, которая не отстает от основных тенденций, наблюдаемых в развитии языков программирования, таких как Java и C#.
  • ООП
  • Java
  • CSharp
  • LINQ
  • Добавить метки

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

    История развития компьютерной техники – это история непрерывного движения от языка и уровня коммуникации машины к уровню пользователя. Если первые машины требовали от пользователя оформления того, что ему нужно (то есть написания программ), в машинных кодах, то языки программирования четвертого уровня (4GLs ) позволяли конечным пользователям, не являющимся профессиональными программистами, получать доступ к информации без детального описания каждого шага, но только с встроенными предопределенными типами данных – например, таблицами.

    Последним шагом в этом направлении стала объектно-ориентированная технология , радикально изменившая сферу разработки программного обеспечения уже в 1990-х годах (Рисунок 1). Объектно-ориентированный подход позволяет упаковывать данные и код для их обработки вместе. Таким образом практически снимается ограничение на типы данных, позволяя работать на любом уровне абстракции.

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

    Обьектно-ориентированные СУБД (ООСУБД ) стали разрабатываться с середины 80‑х годов в основном для поддержки приложений САПР. Сложные структуры данных систем автоматизированного проектирования оказалось очень удобно оформлять в виде объектов, а технические чертежи проще хранить в базе данных, чем в файлах. Это позволяет обойтись без декомпозиции графических структур на элементы и записи их в файлы после завершения работы с чертежом, выполнения обратной операции при внесении любого изменения. Если типичные реляционные базы данных имеют связи глубиной в два уровня, то иерархическая информация чертежей САПР обычно включает порядка десяти уровней, что требует достаточно сложных операций для “сборки” результата. Объектные базы данных хорошо соответствовали подобным задачам, и эволюция многих СУБД началась именно с рынка САПР.

    Между тем рынок САПР был быстро насыщен, и в начале 90‑х годов производители ООСУБД обратили внимание на другие области применения, уже прочно занятые реляционными СУБД. Для этого потребовалось оснастить ООСУБД функциями оперативной обработки транзакций (OLTP), утилитами администратора баз данных (database administrator – DBA), средствами резервного копирования/восстановления и т. д. Работы в данном направлении продолжаются и сегодня, но уже можно сказать, что переход к коммерческим приложениям идет достаточно успешно.

    2. Реляционные базы данных.

    В реляционных базах данных (Relational Database System, RDBS) все данные отображаются в двумерных таблицах. База данных, таким образом, это ни что иное, как набор таблиц. RDBS и ориентированные на записи системы организованы на основе стандарта B-Tree или методе доступа, основанном на индексации – Indexed Sequential Access Method (ISAM) и являются стандартными системами, использующимися в большинстве современных программных продуктов. Для обеспечения комбинирования таблиц для определения связей между данными, которые практически полностью отсутствуют в большинстве программных реализаций B-Tree и ISAM, используется языки, подобные SQL (IBM), Quel (Ingres) и RDO (Digital Equipment), причем стандартом отрасли в настоящее время стал язык SQL, поддерживаемый всеми производителями реляционных СУБД.

    Оригинальная версия SQL – это интерпретируемый язык, предназначенный для выполнения операций над базами данных. Язык SQL был создан в начале 70‑х как интерфейс для взаимодействия с базами данных, основанными на новой для того времени реляционной теории. Реальные приложения обычно написаны на других языках, генерирующих код на языке SQL и передающих их в СУБД в виде текста в формате ASCII. Нужно отметить также, что практически все реальные реляционные (и не только реляционные) системы помимо реализации стандарта ANSI SQL, известного сейчас в последней редакции под именем SQL2 (или SQL-92), включают в себя дополнительные расширения, например, поддержка архитектуры клиент-сервер или средства разработки приложений.

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

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

    Так как все поля одной таблицы должны содержать постоянное число полей заранее определенных типов, приходится создавать дополнительные таблицы, учитывающие индивидуальные особенности элементов, при помощи внешних ключей. Такой подход сильно усложняет создание сколько нибудь сложных взаимосвязей в базе данных. Желающим убедится, что это действительно так и не пожалевшим на это определенный отрезок времени, компания POET Software любезно предоставляет возможность ознакомиться с примером в своей “белой книге” “POET Technical Reference”. База данных рядового предприятия общепита (клиенты – Джордж Буш и Эдди Мэрфи) состоит из четырех таблиц.

    Еще один крупный недостаток реляционных баз данных – это высокая трудоемкость манипулирования информацией и изменения связей.

    3. Объектно-реляционные методы.

    Несмотря на рассмотренные в п. 2 недостатки реляционных баз данных, они обладают рядом достоинств:

    · разделение таблиц разными программами;

    · развернутый “код возврата” при ошибках;

    · высокая скорость обработки запросов (команда SELECT языка SQL; результатом выборки является таблица, которая содержит поля, удовлетворяющие заданному критерию);

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

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

    Существует еще одна причина для применения косвенной адресации: благодаря этому можно отслеживать частоту вызовов объектов для организации эффективного механизма свопинга.

    Это необходимо для реализации уже второго необходимого свойства баз данных – масштабируемости. Опять следует упомянуть организацию распределенных компонентов. Классическая схема клиент-сервер, где основная нагрузка приходится на клиента (такая архитектура называется еще “толстый клиент-тонкий сервер”), лучше справляется с этой задачей, чем мэйнфреймовая структура, однако ее все равно нельзя масштабировать до уровня предприятия. Благодаря многозвенной архитектуре клиент-сервер (N-Tier architecture) происходит равномерное распределение вычислительной нагрузки между сервером и конечным пользователем. Нагрузка распределяется по трем и более звеньям, обеспечивающим дополнительную вычислительную мощность. К чему же еще ведет такая практика? “Архитектура клиент-сервер, еще совсем недавно считавшаяся сложной средой, постепенно превратилась в исключительно сложную среду. Почему? Благодаря ускоренному переходу к использованию систем клиент-сервер нескольких звеньев” (PC Magazine). Разработчикам приходится расплачиваться дополнительными сложностями, большими затратами времени и множеством проблем, связанных с интеграцией. Оставим очередное упоминание распределенных компонентов на этой не лишенной оптимизма ноте.

    Третье необходимое качество базы данных – это отказоустойчивость. Именно это свойство отличает программный продукт от “прилады”. Существуют несколько способов обеспечения отказоустойчивости:

    · резервное копирование и восстановление;

    · распределение компонентов;

    · независимость компонентов;

    · копирование.

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

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

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

    · так называемый “трехфазный монитор транзакций” (third-party transaction monitor), благодаря которому транзакция выполняется не в два, а в три этапа – сначала посылается запрос о готовности к транзакции.

    Что произойдет, если один из компонентов выйдет из строя? Система, созданная в соответствии только с вышеизложенными доводами, приостановит работу всех пользователей и прервет все транзакции. Поэтому важно такое свойство СУБД, как независимость компонентов.

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

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

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

    4.3 Стандарты объектных баз данных.

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

    В области объектных СУБД в настоящее время выработаны стандарты для:

    · объектной модели;

    · языка описания объектов;

    · языка организации запросов (Object Query Language – OQL );

    · “связующего” языка (C++ и, конечно же, Smalltalk);

    · администрирования;

    · обмена (импорт/экспорт);

    · интерфейсов инструментария и др.

    Хотя у Microsoft и свое мнение на этот счет, организацией, выработавшей наиболее используемые на сегодня и устоявшиеся стандарты, является консорциум поставщиков ООСУБД ODMG (ООСУБД), которого поддерживают практически все действующие лица отрасли. В сотрудничестве с OMG , ANSI, ISO и другими организациями был создан стандарт ODMG-93. Этот стандарт включает в себя средства для построения законченного приложения, которое будет работать (после перекомпиляции) в любой совместимой с этой спецификацией ООСУБД. В книгу ODMG-93 входят следующие разделы:

    · Язык определения объектов (Object Definition Language – ODL);

    · Язык объектных запросов (Object Query Language – OQL);


    · Связывание с C++;

    · Связывание со Smalltalk.

    ODL. В качестве языка определения объектов (ODL) ODMG был выбран существующий язык IDL (Interface Definition Language – язык описания интерфейсов), который был дополнен такими необходимыми для объектных БД свойствами, как определение коллекций, двунаправленных связей типа “многие-ко-многим”, ключей и др. В сочетании со средствами языка IDL определения атрибутов и операций, это позволяет определять практически любые объекты. Все дополнения реализованы в виде доопределения методов, что обеспечивает совместимость со стандартами OMG, например стандартом CORBA.

    Рисунок 4 показывает работоспособную схему для построения приложения на стандартных языках программирования, в процессе которой автоматически генерируются метаданные , заголовочные файлы и методы. Приведем также пример на языке ODL из “белой книги” компании Objectivity, который иллюстрирует связи типа “один-ко-многим”, объявленные между преподавателем и студентами:

    interface professor: employee {
    attribute string <32> name;
    unique attribute lang unsigned ssn;
    relationship dept works_in inverse faculty; relationship set

    teaches inverse taught_by; . . . operations . . .
    {
    interface section: class {
    . . . taught_by: professor . . . ;
    . . .
    }

    OQL. За основу языка OQL была взята команда SELECT языка SQL2 (или SQL-92) и добавлены возможность направлять запрос к объекту или коллекции объектов и возможность вызывать методы в рамках одного запроса. Данные, полученные в результате запроса, могут быть скалярными (включая кортежи), объектами или коллекциями объектов. Некоторые примеры на языке OQL (тот же источник):

    Select x from x in faculty where x.salary >
    x.dept.chair.salary
    sort s in (select struct (name: x.name, s:x.ssn) from
    x in faculty where for all y in
    x.advisees:y.age<25) by s.name
    Chair.salary
    Students except TAs
    list (1,2) + list (count (jse.advisees), 1+2)
    exists x in faculty : x.spouse.age<25

    C++. Спецификация ODMG-93 позволяет программистам легко использовать объекты в то время как ООСУБД прозрачным образом управляет ими. При определении стандарта члены ODMG руководствовались следующими принципами:

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

    · Определение временных экземпляров (Transient Instance) и экземпляров, создаваемых на длительный срок (Transient Instance) при помощи оператора new(). При перегрузке оператора new() оба типа экземпляров могут создаваться от одного класса, который может существовать продолжительное время.

    · Обеспечение устойчивости через стандартный механизм наследования; пользователь может определять экземпляры временные и рассчитанные на продолжительное использование средствами оригинальной версии языка.

    · Использование специального механизма указателей (Smart Pointers). Связи между объектами объявляются при помощи шаблона Ref<> и перегрузки оператора ->; это позволяет использовать специальные указатели (контролируемые системой; см., например, идентичность в словарике (стр. 21) и упоминание косвенной адресации (стр. 10) как обычные.

    class Professor: Employee {
    long ssn;
    char* name;
    int age;
    Refdept inverse faculty;
    Set

    teaches inverse taught_by;
    . . .
    void grant_tenure()
    void assign_course(section)
    }
    . . .
    Refprof;
    . . .
    prof = new(db, Professor);
    prof->name="Smith";
    prof->age+prof->age+1;

    На этом, пожалуй, чувство благодарности компании Objectivity в значительной мере ослабеет, так как примеров на языке Smalltalk найти не удалось.

    Smalltalk . ODMG-93 поддерживает ту же объектную модель для Smalltalk, что и для С++, IDL и запросы на языке OQL; это позволяет разделять один и тот же объект пользователям С++ и Smalltalk. Спецификация поддерживает типы (возможны бестиповые поля) и синтаксис оригинальной версии Smalltalk.

    Рисунок 5 ООСУБД, построенная на основе стандартов ODMG во взаимодействии с CORBA.

    Взаимодействие с другими стандартами. Многие стандарты совместимы с объектными базами данных, например STEP, CFI, TINA-C, ISO ODP, ANSI X3H7, OpenGIS и др. Сейчас они могут напрямую взаимодействовать с любой стандартной ООСУБД, хотя в некоторые из них и были внесены изменения для обеспечения совместимости. Два других стандарта заслуживают более детального описания – OMG и SQL .

    Стандарты OMG . Первым результатом деятельности OMG стало утверждение (OMG не создает стандартов, а принимает одну из существующих реализаций) Архитектуры Брокера Объектных Запросов (Common Object Request Broker Architecture – CORBA ) – средства диспетчеризации запросов между объектами и пользователями; в дальнейшем были добавлены некоторые сервисы. Интерфейс ODMG сейчас полностью адаптирован к спецификации Persistence Object Service консорциума OMG, что позволяет пользователям систем, основанных на архитектуре CORBA, пользоваться преимуществами от ООСУБД, которые могут содержать объекты, отвечающие стандарту OMG и используемые так же, как и любые другие (“мелкие”) объекты спецификации OMG (Рисунок 5). Объекты OMG в свою очередь доступны через интерфейс ODMG.

    Язык SQL . Из-за распространенности SQL был заложен в основу OQL , который был дополнен средствами поддержки объектной модели. В настоящее время разрабатывается версия языка SQL, известная под названием SQL3, в которой будут реализована поддержка объектов и SQL будет приведен в соответствие современным понятиям о полноценном языке программирования. В отличие от ODMG, в SQL не планируется привязка к ODL, а также C++ и Smalltalk, которые важны для пользователей ООСУБД. Несмотря на это, возможности SQL3 в организации запросов совпадают с возможностями OQL. Когда SQL3 будет готов (разработки ведутся сейчас на ранней стадии обсуждения основных вопросов относительно объектной модели), ODMG, вероятно, дополнит его, как это уже сделано для С++ и Smalltalk.

    4.4 Поставщики ООСУБД.

    Рисунок 6 Современный рынок СУБД.


    Список современных коммерческих объектно-ориентированных систем включает в себя следующие продукты:

    · Objectivity/DB компании Objectivity, Inc. (последняя версия – 2.1) идеально, по заявлениям фирмы, подходит для приложений, которые работают в распределенных средах, требуют гибкой модификации данных, организации сложных связей, а также нуждаются в высокой производительности и работы с большими объемами данных. Вероятно, все компании, производящие ООСУБД, ставят своей целью сложить такое впечатление относительно собственных разработок у читателей распространяемых ими документов (хотя некоторые и делают это в более деликатной форме). Более содержательно, Objectivity обеспечила интеграцию инструментария СУБД и разработки приложений с такими средствами программирования, как SoftBench и C++ SoftBench. Благодаря интегрированному графическому интерфейсу разработки схемы БД и инструментам отладки и анализа упрощается задание модели базы данных и, соответственно, разработки приложений для Objectivity/DB.

    · СУБД GemStone корпорации GemStone Systems, Inc. известна в последней редакции под номером 5.0. GemStone традиционно сосредоточена на рынке Smalltalk (хотя не так давно и была выпущена версия для С++) и имеет заказчиков, способных продемонстрировать на производстве крупномасштабные, целевые применения ее продуктов. К сожалению, списком этих заказчиков объем информации, которую компания хочет донести до интересующихся (WWW), ограничивается.

    · ONTOS Corp., разработчик СУБД ONTOS (кто бы подумал), по традиции занимается развитием сервера объектно-ориентированной СУБД, но в последнее время придает особое значение своим Службам Интеграции Объектов (Object Integration Services).

    · Построенная на основе реляционной СУБД AllBase, система OpenODB фирмыHewlett-Packard также, как и Objectivity/DB, интегрирована с системой SoftBench и существует в версии для С++. Благодаря глубокой интеграции, SoftBench распознает файлы приложений OpenODB для установки оптимальной конфигурации, может создавать базы данных формата OpenODB из своей интегрированной среды, обеспечивает оперативную помощь из среды разработки и т. д.

    · Object Design Inc. со своей СУБД ObjectStore занимает лидирующее положение в отрасли, осуществляя около 33% поставок на рынке объектно-ориентированных СУБД и последняя модернизация системы (клиент языка SQL и шлюз к реляционной СУБД) должны только укрепить положение фирмы. Object Design поддерживает версии своей СУБД как для С++, так и для Smalltalk.

    · Versant Object Technology, Inc. (СУБД Versant ) проводит двойную стратегию, предлагая средство обеспечения объектно-ориентированной СУБД высокого класса для телекоммуникаций и инструментальные средства Smalltalk для более общих случаев разработки приложений. Используя разработанный фирмой интерфейс VERSANT Smalltalk Language Interface, СУБД совместима как с версией языка Smalltalk компании ParcPlace-Digitalk, так и с Visual Age for Smalltalk корпорации IBM.

    · СУБД UniSQL компании UniSQL Inc. – хорошо устоявшаяся система, позволяющая пользователям осуществлять запросы и модификацию базы при помощи разработанного компанией языка SQL/X (подобные языки, носящие условное название Object SQL, разработаны и некоторыми другими поставщиками). Вся БД UniSQL может состоять одновременно из связей в локальных РСУБД и классов в локальных объектных базах UniSQL. Благодаря механизму каталогов, СУБД передает запросы и модификации данных в локальные базы данных и, обработав (перевод в другой формат, группирование, сортировка и т. д.) полученный от них результат, возвращает его пользователю.

    Кроме того ООСУБД предлагают: Object Database, Inc. (Object Database), Itasca Systems Inc. (Itasca) O2 Technology (O2) и некоторые другие компании.

    5. Заключение.

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

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

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

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

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

    6. Глоссарий


    4GL (4 th Generation Language) – Язык программирования четвертого поколения ¨Язык программирования, при создании которого используются языки программирования третьего уровня (3GL) – процедурные языки типа C и Pascal. 4GL проще в использовании, чем 3GL, им обычно отдают предпочтение при составлении программ обслуживания баз данных и применяют в сочетании с соответствующими средствами разработки.

    Blob (Binary Large Object) – Двоичный большой объект, блоб. ¨Длинный линейный блок данных (например, цифровое изображение или видеоклип), который наиболее подходит для хранения в ООСУБД .

    CORBA (Common Object Request Broker Architecture) Архитектура брокера объектных запросов ¨Стандарт взаимодействия распределенных компонентов, разработанный OMG .

    DBMS (Database Management System) – Система управления базами данных, СУБД

    N - звенная архитектура (N-Tier Model) ¨Архитектура клиент-серврер , в которой применяются средства разбиения программ или распределенные объекты для разделения вычислительной нагрузки среди такого количества серверов приложений, которое необходимо при имеющемся уровне нагрузки. При многозвенной модели системы количество возможных клиентских мест значительно больше, чем при использовании двухзвенной модели. См также middleware .

    ODBMS (Object Database Management System) – Объектно-ориентированная СУБД ООСУБД . ¨СУБД, хранящая данные и взаимосвязи между ее элементами непосредственно в самой базе данных в виде объектов, содержащих, как правило, алгоритмы обработки этих данных.

    ODMG (Object Database Management Group) ¨Консорциум производителей объектных баз данных для выработки стандартов (ODMG-93, ODMG-95).

    OMG (Open Management Group) ¨Консорциум поставщиков в сфере объектной технологии для выработки стандартов межкомпонентного взаимодействия. Объединяет практически всех ведущих производителей (более чем 500); членство Microsoft, видимо, лишь условно.

    OQL (Object Query Language) Язык объектных запросов ¨Разработанный консорциумом ODMG язык описания запросов, за основу которого был принят SQL -92.

    RDBMS (Relational Database Management System) – Реляционная СУБД – СУБД , хранящая взаимосвязи между элементами в виде двумерных таблиц и использующая для запросов язык SQL .

    SQL (Structured Query Language) – Язык структурированных запросов ¨Интерпретируемый язык, описывающий операции (создание, обработка и извлечение) над реляционными базами данных.

    Архитектура клиент-сервер (Client-server architecture) ¨Архитектура, обеспечивающая распределение нагрузки между клиентом и сервером. Обычно эти функции выполняют два разных компьютера, объединенных при помощи сети.

    Атрибуты (Attributes) ¨Видимая за пределами объекта информация о состоянии этого объекта.

    “Белая книга” (White Paper) ¨Официальное издание.

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

    Идентичность (Identity) ¨Возможность получения уникального адреса объекта независимо от его местоположения и атрибутов .

    Инкапсуляция (Encapsulation) ¨Объединение данных и кода в один модуль – объект, доступ к которому может осуществляться только через строго определенный интерфейс.

    Метаданные (Metadata) ¨Данные, являющиеся описанием других данных (например, схема базы данных по отношению к ее содержимому).

    Наследование (Inheritance) ¨Механизм, благодаря которому определения класса распространяется на классы, лежащие ниже его в иерархии обобщения классов. Это позволяет многократно изменять определения, внося по мере необходимости изменения, связанные со специализацией.

    Объектно-реляционные методы (Object-relational Approaches) ¨Подходы, позволяющие воспользоваться преимуществами объектных баз данных, не отказываясь полностью от реляционных БД.

    Отображение (Mapping) ¨Процесс установления связей между приложениями, построенными вокруг объектно-ориентированных и реляционных баз данных.

    Полиморфизм (Polymorphism) ¨Способность объектов различных классов и самих классов удовлетворять одним и тем же протоколам или отдельным сообщениям, выполняя при этом различные действия, предписываемые их собственными методами.

    Промежуточное обеспечение (Middleware) ¨ПО, служащее посредником между клиентом и сервером, например, для предоставления общих интерфейсов. Следуя традиции, и я тоже напишу, что промежуточное ПО – это слэш в термине “клиент/сервер”.

    Протокол (Protocol) ¨Набор сообщений, на которые может ответить класс (протокол класса) или его объекты (протокол объекта). Протокол определяется заданными методами. Все объекты одного класса отвечают одному протоколу.

    СУБД Система Управления Базами Данных.¨Лежащая в основе базы данных прикладная программа, выполняющая операции над хранимой информацией.

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

    vdbms 20 декабря 2017 в 14:59

    Простая объектная СУБД

    • Алгоритмы ,
    • Анализ и проектирование систем ,
    • Программирование

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

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

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

    Объект данных

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

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

    Априори объект содержит набор значений, которые идентифицируются по их порядковому номеру в наборе. Сам объект свои значения никак не интерпретирует, но «знает», что каждое значение характеризуется длиной в байтах, что позволяет вычислить размер объекта. Набор значений существует в формате кортежа.

    Идентификация и доступ

    Для хранения объектов используется условно бесконечное файловое пространство, логически разбитое на кластеры. В файловом хранилище каждый объект занимает один или более последовательных кластеров. Порядковый номер первого кластера используется в качестве файлового указателя FP (File Pointer) на размещение объекта в хранилище.

    Для долговременного хранения файловых указателей используется таблица аллокации DAT (Data Allocation Table), которая представляет собой простой динамически расширяемый массив целочисленных указателей. Индексы ячеек DAT используются в качестве системных идентификаторов объектов IDO . Когда создается новый объект, ему выделяется очередная свободная ячейка DAT, индекс которой становится постоянным идентификатором объекта. Этот идентификатор является уникальным и глобальным дескриптором объекта в пределах физической базы данных.

    При старте системы DAT загружается из хранилища в оперативную память, и используется для организации быстрого доступа к объекту по его IDO по следующей схеме:

    Если извлеченное из DAT значение представляет собой файловый указатель, то объект загружается из хранилища в память - Cache объектов , и содержимое ячейки DAT подменяется указателем на память A* . Обратная замена происходит при вытеснении объекта из памяти.

    Обратим внимание: указатель на память A* - это не абсолютный адрес, а лишь смещение относительно начала Cache , но указывает он непосредственно на содержимое объекта. Заголовок объекта, а также служебные поля, предназначенные для временного хранения FP и связывания объектов в цепочки, расположены относительно A* с отрицательным смещением. Примечательно, что значение A* также используется в качестве идентификатора объекта в памяти.

    Cache объектов

    Представляет собой непрерывную область памяти, статически выделенную при инициализации системы. Требуемый размер задается опционально.

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

    Состояния и транзакции

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

    Внешнее воздействие, изменяющее состояние базы данных, рассматривается как транзакция .

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

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

    Целостность данных

    Концепция транзакционной целостности общеизвестна - "все, или ничего ".

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

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

    Необходимость соблюдения "состоятельной " целостности данных далеко не столь очевидна.

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

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

    Объекты состояния

    Как минимум одно состояние базы данных - фоновое , актуально всегда. Фоновое состояние образовано полным множеством объектов, непосредственно адресуемых из DAT, из которых часть осталась на диске, а часть загружена в память.

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

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

    Ранее упоминалось, что попытка изменить существующий объект автоматически порождает его новую версию. Таким образом, одновременно в памяти могут находится несколько версий одного и того же объекта. Эти версии связаны в одноименную цепочку. Указатель (A* ) на первый объект в цепочке версий находится в DAT, а сама цепочка позволяет пользователю получить доступ к «правильной» версии объекта в требуемом состоянии. При этом корректной (актуальной с точки зрения пользователя) считается версия с наибольшим номером состояния, не превышающим требуемый.

    Распределение по состояниям объектов, связанных в цепочки состояний и версий, выглядит примерно так:

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

    Для управления многопользовательским доступом, состояниями базы данных и их объектами используется таблица состояний ST (States Table).

    Таблица состояний

    Каждая запись ST содержит указатель (A* ) на первый объект цепочки объектов состояния, идентификаторы пользователя и объекта блокировки, а также счетчик пользователей, использующих это состояние.

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

    Указатель Background State (BS ) содержит номер фонового состояния. При поглощении последующего временного состояния указатель BS инкрементируется. Условием поглощения является нулевое значение счетчиков использования сразу двух состояний: фонового и следующего за ним. Условие проверяется при закрытии любой из сессий, после декремента счетчика использования.

    Указатель Last Available State (LS ) содержит номер самого старшего состояния из доступных. Этот номер предоставляется пользователю при открытии им сессии выборки. Когда очередная транзакционная сессия закрывается, указатель LS инкрементируется, автоматически получая номер этой сессии.

    Указатель Next State (NS ) предоставляет номер состояния пользователю, открывающему транзакционную сессию, после чего инкрементируется. Если открытых транзакционных сессий нет, то значение NS превышает значение LS на 1. Если нет временных состояний, то значения указателей BS и LS совпадают.

    Номер состояния, получаемый пользователем при открытии любой сессии, сохраняется в соответствующей записи таблицы клиентов CT (Client Table). Все обращения пользователя к API сервиса объектов включают в себя идентификатор клиента, а остальные данные извлекаются из соответствующей записи CT.

    Таблица клиентов

    Системный идентификатор клиента - это порядковый номер записи, выделенной ему в Client Table при авторизации. В этой таблице регистрируются как системные ресурсы, выделенные клиенту: дескрипторы TCP-сокета и потока, так и ресурсы, используемые им в системе управления данными, и в частности - номер открытого пользователем состояния, а также различные управляющие флаги.

    Разрешение конфликтов

    Напомним: транзакции, независимо от их продолжительности и результата, должны завершаться строго в том порядке, в котором они были начаты, по возрастанию собственных номеров. Для организации такой очередности используется пул именованных объектов блокировки, которые создаются совместно с таблицей ST при инициализации системы.

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

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

    При наличии предыдущей незавершенной транзакции, текущая, пытаясь избежать конфликта, меняет логику своего исполнения. Вспомним, что обращение к диску является самой продолжительной из всех операций, выполняемых сервисом объектов. Поэтому, пока предыдущая транзакция исполняется, текущая только лишь имитирует свое исполнение - без реального создания копий объекта и изменения их содержимого. При этом все объекты, которые так или иначе были использованы транзакцией, гарантировано окажутся загружены в Cache. Когда имитационное исполнение завершено, то транзакция повторно проверяет запись ST предыдущего состояния. Если идентификатор объекта блокировки из нее получен, то транзакция «зависает» в попытке захватить этот объект. После освобождения объекта блокировки предыдущей транзакцией, текущая продолжит свое исполнение, но теперь уже в штатном режиме и с минимальным временем исполнения.

    Нештатные ситуации

    Если что-то пошло не так (например, фатальная ошибка сервиса объектов или аппаратный сбой), то спасти базу данных может только авто-восстановление из контрольной точки. В более же мягком случае, когда поток клиента «упал и не отжался», или ушел в бесконечность, оставив свою сессию открытой, полную остановку конвейера состояний можно предотвратить.

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

    Зависание сессии выборки будет обнаружено только тогда, когда исчерпаются все свободные записи ST, то есть когда индексы BS и NS сравняются. Зависшее состояние с индексом или будет иметь не нулевое значение счетчика использования.

    Безотносительно причины аварии сессии, ее последствия всегда одинаковы: после получения идентификатора «зависшего пользователя» его поток принудительно останавливается, все использованные ресурсы освобождаются, сессия принудительно завершается, после чего конвейер самостоятельно разгружается уже в штатном режиме. Все эти действия выполняются в потоке пользователя, обнаружившего проблему. По завершении восстановительных операций поток зависшего пользователя запускается снова, и он предпринимает как минимум одну попытку повторить неудачную сессию заново. В случае второй неудачи пользователь начинает свой поток с ожидания внешних событий. Весь этот процесс регулируется флагами, выставляемыми пользователю в Client Table.

    Кортеж значений

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

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

    Кортеж обладает рядом замечательных свойств.

    Прежде всего, значением в кортеже может быть другой кортеж. С этой точки зрения все содержимое объекта можно рассматривать как одно значение. Длина любого значения известна из его заголовка, а значит известно и количество элементов в кортеже.

    Порядок следования элементов в кортеже строг и неизменен. Операция «Вставка» запрещена. Но можно безболезненно добавлять к имеющемуся набору новые элементы.

    В кортеже не инициализированное значение будет иметь нулевое значение смещения, чем и отличается от «пустого» значения с нулевой длиной. Не инициализированным значением можно бесконфликтно оперировать, в том числе рассматривая его как «пустое» значение.

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

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

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

    Две последние из перечисленных особенностей поведения кортежа активно используются при модификации объекта в ходе транзакционной сессии.

    Изменение объекта

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

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

    Сохранение объектов

    Файловое пространство, выделяемое для хранения объектов, не только кластеризовано, но и разбито на банки данных размером два в степени N кластеров. Каждый банк занимает один файл, который именуется последовательным номером банка. Таким образом, при обращении к объекту на диске, его FP последовательно конвертируется сначала в имя файла, а затем в номер кластера в файле.

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

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

    После завершения сессии измененные объекты транзакции в Cache становятся общедоступны в том виде как есть, а именно - с неполным кортежем. Эти объекты должны заместить собой предыдущие версии.

    Слияние версий

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

    Версия , как правило подгруженная с диска, занимает непрерывную область в Cache, в то время как кортеж и новые значения версии [+1] находятся в разных местах, усиливая дефрагментацию памяти. Поэтому сценарий поглощения версии [+1] выглядит привлекательнее сценария вытеснения версии . Если новое значение версии [+1] по размеру не превышает имеющееся, то оно просто копируется в тело версии , и занимаемая им память освобождается. Иначе это новое значение остается за пределами объекта как есть, и для него вычисляется новое смещение, а объекту выставляется флаг, обязывающий процесс обычного вытеснения анализировать объект на наличие фрагментов за его пределами.

    Формализация транзакций

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

    Стоит отметить, что порядок постановки в очередь транзакции и банка объектов, сформированных в ходе закрытия одной сессии, определяется тем, удалось ли разместить объекты транзакции в этом банке. Если удалось, то формализованная транзакция помещается в очередь первой. Если для размещения объектов данной транзакции был открыт новый банк, то первым в очередь ставится банк объектов.

    Последовательность формализованных транзакций, сохраненных на диске, образует журнал транзакций.

    Журнал транзакций

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

    Помимо этого стоит отметить, что у журнала есть еще одна функция – фискальная, которая не раз доказывала свою полезность в разборках типа " … это программа накосячила".

    Запись на диск

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

    Тип данных определяет целевой файл, в который будут записываться данные. Основных типов данных всего три: формализованные транзакции, банки объектов и DAT.

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

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

    В результате действий потока записи файловое хранилище принимает следующий вид:

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

    Контрольная точка

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

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

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

    Сборка мусора

    В нашем распоряжении всего два физических ресурса: память и такты процессора. А так как в приоритете производительность, то следствием является повышенный расход памяти. Так, с целью уменьшить объем файловых операций, новые и измененные объекты сохраняются на диске оптом, одним файлом. При этом более ранние версии изменяемых объектов остаются на прежних местах в предыдущих банках и уже никогда не будут использованы. Чтобы вернуть системе дисковую память, внутренне «поредевший» банк необходимо периодически «уплотнять», уменьшая его размер, и не забывая при этом внести изменения в DAT и перезаписать архивную копию банка. Для облегчения анализа заполненности банков, сервис объектов перманентно поддерживает в актуальном состоянии битовую карту кластеров.

    Архитектура сервера

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

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

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

    Внутренняя логика Модели и Курсоров, а также способы ее реализации - тема отдельного рассказа.

    Масштабируемость

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

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

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

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

    За кадром

    Как это часто случается при изложении достаточно объемного материала, было пропущено много относительно мелких и второстепенных деталей. Так например, не были упомянуты: сегментирование и дублирование DAT в памяти; особый порядок управления «большими» объектами; принципы организации взаимных блокировок потоков пользователей при доступе к общим ресурсам; логика и реализация сборки мусора; отображение процесса исполнения в log-журнал; сбор и отображение статистики; и многое другое.

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

    Резюме

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

    Материал публикуется с надеждой, что будет полезен всем, кто интересуется архитектурой баз данных.

    Теги:

    • базы данных
    • объектная СУБД
    • архитектура системы
    Добавить метки

    Прежде, чем перейти к обсуждению организации некоторых объектно-ориентированных СУБД, следует коротко рассмотреть оказавшие на них влияние предшествующие архитектуры СУБД, а также архитектуры, не являющиеся в традиционном понимании объектно-ориентированными, но близкие по прагматике. Из числа архитектур с традиционной организацией наибольшее влияние на объектно-ориентированные СУБД оказали реляционные системы. Многие объектно-ориентированные системы (по крайней мере, в прототипных вариантах) строятся над некоторой существующей реляционной СУБД. Кроме такого применения реляционных систем для упрощения разработки объектно-ориентированной СУБД, развитые в реляционных СУБД методы применяются и в заново разрабатываемых объектно-ориентированных системах. Непосредственным предшественником объектно-ориентированных СУБД являются системы, поддерживающие организацию сложных объектов. Эти постреляционные системы большей частью появились по причине несоответствия возможностей реляционных СУБД потребностям нетрадиционных приложений (автоматизация проектирования, инженерия и т.д.). По сути дела, в таких системах частично поддерживается структурная часть объектно-ориентированных БД (без возможностей наследования). Многие объектно-ориентированные СУБД (в частности, ORION) разрабатывались на базе предыдущих работ со сложными объектами.

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

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

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

    Рассматривая особенности чисто объектно-ориентированных СУБД, следует выделить двух систем - ORION и O2.

    Основными функциональными компонентами первой системы являются подсистемы управления памятью, объектами и транзакциями. В ORION-1 все компоненты, естественно, располагаются в одной рабочей станции; в ORION-1SX - разнесены между разными рабочими станциями (в частности, управление объектами производится в рабочей станции-клиенте). Применение в ORION-1SX для взаимодействия клиент-сервер механизма удаленного вызова процедур позволило использовать в этой системе практически без переделки многие модули ORION-1. Сетевые взаимодействия основывались на стандартных средствах операционных систем.

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

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

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

    Основными компонентами системы в проекте O2, не считая развитого набора интерфейсных средств, являются интерпретатор запросов и подсистемы управления схемой, объектами и дисками. Управление дисками, т.е. поддержание базовой среды постоянного хранения обеспечивает система WiSS, которую разработчики O2 перенесли в окружение ОС UNIX.

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

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


    Есть вопросы?

    Сообщить об опечатке

    Текст, который будет отправлен нашим редакторам: