Объектно-ориентированные базы данных.

  Банников Н.А. www.stikriz.narod.ru Почта На главную страницу  

Начала.  
Перспективы.  

Вариант реализации.  

Архитектура.  

Структура БД.  

Приложение пользователя.  

Сервер приложений.  

Роботы.  

Оценка производительности .  

Факторы, влияющие на производительность.  

Заключение.  

Глоссарий.

Рейтинг@Mail.ru

 

Вначале было Слово. И Слово было у Бога.

Начала.

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

Давайте для начала разберемся, о чем идет речь. Что такое объектно-ориентированная база данных? Давайте посмотрим на этот вопрос девственно чистым взглядом. Отбросим свой опыт – читай комплексы. Отбросим убежденность в бесперспективности и не реализуемости, если у кого такая убежденность есть. Не будем думать, пока, о производительности, планах и индексах. Итак, что же такое объектно-ориентированная БД, далее ООБД?

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

На данном этапе развития IT индустрии, имея мощные языки программирования, такие как C++ и Object Pascal, CASE средства, такие как Rational Rouse, нам до сих пор приходится старым дедовским методом определять описания данных в реляционной модели. Нам до сих пор приходится бесконечно латать свои проекты, увязать в тонкостях обработки данных, только потому, что хранилища данных никак не стыкуются со средствами разработки. А жизнь не стоит на месте и диктует все новые и новые правила. Я имею в виду, что в описательных возможностях современных баз данных отсутствуют основополагающие принципы объектной ориентированности. Это печально. И уж совсем печально то, что поставщики реляционных механизмов пытаются на этом фоне иметь бодрое лицо, заявляя о прорывах, то анонсированием недо-объектных механизмов, например Oracle, то, совсем неуместно крича, о неком прорыве, такие как  Cache, отметая по пути реляционную модель. Нужно просто и ясно сказать, что это не то, что нам нужно. А нам нужно три простых принципа: инкапсуляция, наследование и полиморфизм. Вот, сказал. А что же это значит для БД?

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

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

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

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

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

Первый термин для рассмотрения – это понятие объекта. Вот две фразы из жизни программиста. Первая: «Мой объект разрушился и «Винда» выдала синий экран L.». Вторая: «Я создал объект – наследник от TDataSet – рулез, да и только J.» Из контекста понятно, что в первом случае речь идет об экземпляре типа, а во втором – об описании класса в интерфейсной части модуля. Я знаю только один вариант, когда обе фразы пусть не совсем, но могут быть одновременно почти правильными – это запись в языке Си:

 

struct            {

                           unsigned int Value;

                           … тра-ля-ля …

               } MyStruct;

 

Но, очень трудно представить, чтобы он разрушился, да и не объект это… Т.е. в отношении понятия объекта нет ясного представления даже у некоторых профессионалов. Давайте так всё и оставим. Давайте, определять точное значение этого термина из контекста повествования. Это тем более полезно, т.к. можно говорить об объекте реального мира, который мы описываем, об объекте как описании типа данных, об объекте как экземпляре типа и т.д. Я не могу настаивать, но, как правило, употребляю термин объект в значении «объект реального мира», который нужно описать в базе данных. Поэтому, когда говорят объект применительно к данным в объектно-ориентированной БД, то это и есть одновременно и описания и данные в проекции объекта реального мира и его поведенческая модель. Т.е. с точки зрения лингвистики в таком подходе противоречия нет.

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

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

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

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

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

Перспективы.

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

Всё ПО, с точки зрения эксплуатационных возможностей, можно разделить на три категории. Первая и самая благодатная для производителей ПО – это категория программ общего назначения. К ним относятся не только офисные программы, но и серверы баз данных, всевозможные графические редакторы, компиляторы, RAD, такие как Delphi или VB и другие. Отличительная особенность этих программ состоит в том, что с их помощью можно создать законченный продукт или они диктуют правила игры при работе с такими программами. Например, серверы баз данных способны создавать базу данных, которая уже сама по себе является отдельной законченной единицей конечного продукта. Благодаря языку SQL и многочисленным инструментам доступа к таким БД через сервер, возможно использования созданных ими БД в различных программах, написанных на различных языках.  Офисные программы позволяют создать документ, электронную таблицу, или, например, страничку в Internet, которые так же являются законченными продуктами деятельности и не нуждаются в дальнейшей обработке другими программами. Или это невозможно, но пользователь, который нуждается в дальнейшей обработке своего труда просто переходит на другое ПО, понимая и соглашаясь с ограничениями офисного ПО.

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

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

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

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

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

 

1.      От простого к сложному.

2.      Повторное использование.

3.      Самодокументируемость.

4.      Все в одном или единое информационное пространство.

 

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

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

Вариант реализации.

 

Теперь, можно поговорить о вещах более интересных для программистов. Мы поговорим об одном из способов реализации ООБД. Я не знаю, кто именно первый придумал такой способ, но лично я пришел к нему самостоятельно где-то перед Новым Годом в 1995 году. А первая экспериментальная версия программы была закончена весной 1996 года. В 1999 году я первый раз встретил в Internet описание «моего» способа. И судя по структуре предлагаемой базы, она развивалась тоже не первый год. Собственно, это и неважно кто первый, а сама мысль, что не один человек так поступает должна вселить в нас уверенность, что мы на верном пути. И здесь, собственно, я не буду рассказывать, как именно сейчас я делаю ООБД. Я постараюсь показать, как должно её сделать на основе моих последних представлений.

Архитектура.

Прежде всего, нужно разобраться с архитектурой программного комплекса. Давайте, не будем ориентироваться на какой-нибудь особенный сервер базы данных, а постараемся обойтись стандартом SQL 92. Возможно, что в реализациях под разные серверы, разработчик все-таки будет использовать его наиболее сильные стороны, но это нужно закладывать не в структуру БД, а в настройки. Или, если в структуру БД, то так, чтобы это было прозрачно для пользователя. Например, можно использовать триггеры в InterBase, т.к. они не требуют никаких дополнительных телодвижений при пользовании базой. Второй постулат – это необходимость реализации трехзвенной архитектуры. И для этого есть ряд причин. Основные из них – это необходимость разгрузить приложение пользователя от ненужных обменов по сети описаниями базы, унификация интерфейса между прикладной задачей и сокрытие от приложения пользователя всех тонкостей реализации работы с ООБД. Пусть приложение думает, что работает с обычными плоскими таблицами. Пусть процесс авторизации по запросу от клиентской программы выполняется на сервере приложений, а не на рабочей станции. И последнее – это необходимость убрать ядро ООБД на сервер приложений, а приложению пользователя дать возможность работать только с интерфейсом пользователя. Вообще, если строить интерфейс пользователя как настраиваемый в Run Time, то приложению пользователя достаточно уметь авторизировать пользователя на сервере приложений и загрузить главное окно. Все остальное – это настройки в ООБД.

Структура БД.

Нам нужна база, в которой можно хранить любые данные, причем, структура базы не должна меняться, чтобы не нужно было перекомпилировать программу, если появляется новый тип данных или в БД происходят какие-то другие изменения, даже самые кардинальные. Но, какие же могут быть изменения, тем более, самые кардинальные, если мы не меняем структуру БД. Это только на первый взгляд может показаться парадоксальным. Как мы в дальнейшем увидим – парадокса никакого нет. Как я рассуждал? Вот, мы нормализуем базу, чтобы структурировать данные, чтобы вынести отдельные понятия в отдельные справочники. Тогда база становится понятней, легче сопровождается, и как побочный эффект, возможно, даже, уменьшается в размерах. Сам процесс нормализации, по-простому, выглядит как перемещение данных одного из столбиков в другую таблицу. А в главной таблице вместо этого столбика остается значение ключа, связывающего главную таблицу с таблицей справочника. И этот процесс повторяется, если нужно со справочниками, и так далее. Но, почему-то мало кто замечает, что мы,  в принципе, можем нормализовать базу не в прикладных понятиях, а в понятиях низкоуровнего представления данных. И тогда картина резко изменится. Мы создадим одну главную таблицу, а значения, которые представляют собой данные, разнесем по разным таблицам. В одной таблице будем хранить только целые числа, во второй – дробные, в третьей – строки и так далее по списку возможных типов данных сервера БД. И вот, когда мы это сделаем, то у нас получится такая каша в БД, что непросто будет в ней разобраться не только нам, но и любой программе. Я бы даже сказал невозможно. На этом можно было бы и остановится, провозгласив неразрешимость задачи. Но мы не остановимся. А что произошло? Ничего особенного, просто, нам нужно восстановить полную декомпозицию – вот и все. Мы же не раз и не два её восстанавливали.

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

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

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

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

Для примера возьмем базу для InterBase. Вот как будет выглядеть такая структура:

 

CREATE TABLE TYPE_LIST /*  Список типов */

(

 ID_NUM INTEGER NOT NULL,

 NAME_TYPE VARCHAR(40),

 CAPTION VARCHAR(40),

 PRIMARY KEY (ID_NUM);

);

 

CREATE TABLE PROP_LIST /*  Список свойств */

(

 ID_NUM INTEGER NOT NULL,

 ID_TYPE INTEGER NOT NULL,

 TYPE_PROP SMALLINT,

 NAME_PROP VARCHAR(40),

 CAPTION VARCHAR(40),

 PRIMARY KEY (ID_NUM),

 FOREIGN KEY (ID_TYPE) REFERENCES TYPE_LIST(ID_NUM);

);

 

CREATE TABLE DATA_LIST /* Данные */

(

 ID_NUM INTEGER NOT NULL,

 ID_TYPE INTEGER NOT NULL,

 PRIMARY KEY (ID_NUM);

);

 

CREATE TABLE VAL_INT /* Целые числа */

(

 ID_NUM INTEGER NOT NULL,

 ID_PROP INTEGER NOT NULL,

 VAL INTEGER,

 PRIMARY KEY (ID_NUM, ID_PROP);

);

 

… /* Остальные таблицы низкоуровневых форматов данных */

 

CREATE TABLE VAL_STR /* Строки*/

(

 ID_NUM INTEGER NOT NULL,

 ID_PROP INTEGER NOT NULL,

 VAL VARCHAR(128),

 PRIMARY KEY (ID_NUM, ID_PROP);

);

 

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

 

SELECT V0.VAL AS NUMBER_DOCUMENT, V1.VAL AS DATE_DOCUMENT

FROM DATA_LIST D

JOIN VAL_INT V0 ON ( D.ID_NUM = V0.ID_NUM AND V0.ID_PROP = 204 )

JOIN VAL_DATE V1 ON ( D.ID_NUM = V1.ID_NUM AND V1.ID_PROP = 205 )

WHERE D.ID_TYPE = 35

 

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

 

Select NUMBER_DOCUMENT, DATE_DOCUMENT

From Document

 

Но, документ в справочнике под номером 35, свойство номер – 204, а свойство дата – 205. Номер целого типа, значит искать его нужно в таблице целых чисел, т.е. VAL_INT, а дата, соответственно, в таблице VAL_DATE.

Что делать, если нужно организовывать справочники, т.е. создать в ОООБД что-то вроде FOREIGN KEY? Для этого можно создать таблицу ссылок на другие записи, например, так:

 

CREATE TABLE VAL_POINT

(

 ID_NUM INTEGER NOT NULL,

 ID_PROP INTEGER NOT NULL,

 VAL INTEGER NOT NULL,

 PRIMARY KEY (ID_NUM, ID_PROP);

 FOREIGN KEY (VAL) REFERENCES DATA_LIST (ID_NUM);

);

 

Чтобы двигаться дальше, нужно уточнить ряд моментов. Так, при вставке новой записи в DATA_LIST, необходимо триггером добавлять все необходимые записи в таблицы с данными, При удалении – соответственно, удалить. Нужно запретить в триггере редактирование клиентом полей, которые являются ключами, например, ID_NUM, ID_TYPE и ID_PROP в каких бы таблицах они не встречались. Это необходимо для сохранения правильной структуры ООБД.

И о печальном. Не каждый сервер БД подходит для такой структуры базы данных. Предпочтительным, конечно является версионник. Любой блокировщик, например MS SQL при режиме транзакции ReadCommited при интенсивной нагрузке, очень быстро начнет блокировать страницами, а если все уже на этом этапе не встанут, то рано или поздно заблокирует всю таблицу DATA_LIST. А ведь она у нас одна на все данные в БД! И нельзя ни в коем случае её блокировать. Хотя, можно подключаться в грязном чтении, но тогда необходима специальная таблица блокировок, работа которой могла бы поддерживаться сервером приложений. Но, тогда при малейшем сбое или зависании, или падении сервера приложений в таблице блокировок останутся записи, которые придется чистить администратору вручную. А это как-то не по людски. Т.е. либо InterBase либо Oracle? Да… Выбор какой-то не богатый. Но, особо жаждущие преодоления бесполезных трудностей могут использовать и блокировщик. Тем более, что я видел в Internet описания похожей базы написанной на MS SQL Server.

Продолжим. Как организовать WHERE? Наш запрос можно немного переделать:

 

Select NUMBER_DOCUMENT, DATE_DOCUMENT

From Document

Where NUMBER_DOCUMENT = 33

 

Тогда запрос, реально отсылаемый на сервер БД будет таким:

 

SELECT V0.VAL AS NUMBER_DOCUMENT, V1.VAL AS DATE_DOCUMENT

FROM DATA_LIST D

JOIN VAL_INT V0 ON ( D.ID_NUM = V0.ID_NUM AND V0.ID_PROP = 204 )

JOIN VAL_DATE V1 ON ( D.ID_NUM = V1.ID_NUM AND V1.ID_PROP = 205 )

WHERE D.ID_TYPE = 35  AND

V0.VAL = 33

 

Но, по идее, можно и более эффективно, например, так:

 

SELECT V0.VAL AS NUMBER_DOCUMENT, V1.VAL AS DATE_DOCUMENT

FROM DATA_LIST D

JOIN VAL_INT V0 ON ( D.ID_NUM = V0.ID_NUM AND V0.ID_PROP = 204  AND V0.VAL = 33)

JOIN VAL_DATE V1 ON ( D.ID_NUM = V1.ID_NUM AND V1.ID_PROP = 205 )

WHERE D.ID_TYPE = 35

 

Правда, у меня сервер InterBase 6.01 падал от таких запросов, если условий было много, но ведь, жизнь не стоит на месте и ошибки, возможно, уже исправлены?

Сортировка. Понятно, что сортировки можно сделать, указав номер столбика, например, order by 1 для номера. Но, практика показывает, что, по крайней мере, для InterBase сортировку лучше не указывать, а производить её на клиентской стороне, т.к. это значительно быстрее.

Теперь, поговорим о механизмах наследования. В нашей БД, пока нет наследования. Чтобы оно появилось, достаточно добавить дополнительное поле в справочник типов, в котором хранить номер предка:

 

CREATE TABLE TYPE_LIST /*  Список типов */

(

 ID_NUM INTEGER NOT NULL,

 ID_PARENT INTEGER NOT NULL,

 NAME_TYPE VARCHAR(40),

 CAPTION VARCHAR(40),

 PRIMARY KEY (ID_NUM);

);

ADD FOREIGN KEY (ID_PARENT) REFERENCES TYPE_LIST (ID_NUM);

 

Что нам это дает? При вставке новой записи в таблицу TYPE_LIST, если ID_PARENT <> ID_NUM, то в триггере можно скопировать свойства от типа с номером ID_PARENT в тип, который вставляется. Можно для поддержки RTTI написать процедуру, наподобие is в Delphi. Можно сделать парсер, который сможет строить объектно-ориентированные запросы для выборки в один набор данных из разных типов. Можно в триггере контролировать и запрещать удаление у предка свойств, если от него наследуются другие типы. И запрещать в триггере удаление у потомков свойств, если оно есть у предка. Можно написать процедуру, которая вернет всех потомков у предка.

Рассмотрим такой запрос:

 

Select NUMBER_DOCUMENT, DATE_DOCUMENT

From (PlatPor, Nakladnaya) as Document

Where IS_PRINT = ‘F’

 

Т.е. выбрать все платежки и накладные, которые заведены, но не распечатаны, и показать их номера и дату. Понятно, чтобы выслужится у начальства, заодно заложить соседа по кабинету. Как это может выглядеть в ОООБД?

 

SELECT V0.VAL AS NUMBER_DOCUMENT, V1.VAL AS DATE_DOCUMENT

FROM DATA_LIST D

JOIN VAL_INT V0 ON ( D.ID_NUM = V0.ID_NUM AND V0.ID_PROP = 204  )

JOIN VAL_DATE V1 ON ( D.ID_NUM = V1.ID_NUM AND V1.ID_PROP = 205 )

WHERE D.ID_TYPE  IN (

305, 268) AND

D.ID_NUM IN (

SELECT V2.ID_NUM

FROM VAL_BUL V2

WHERE V2.ID_PROP = 207 AND

V2.VAL = ‘F’ )

 

Здесь парсер сначала проверяет, что PlatPor и Nakladnaya являются потомками Document. Затем, строит запрос как будто для типа Document, но вставляет вместо номера типа документа номера типов PlatPor и Nakladnaya. Здесь отчетливо видно, что номера и имена свойств потомков должны быть в точности такими же, как у предка. Конструкция со вторым AND ограничивает выходной набор теми записями, которые удовлетворяют WHERE в исходном человеческом запросе.

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

Приложение пользователя.

Спустя несколько лет после выхода Delphi1 наша братия программистов наконец-то разобралась с RTTI. Спасибо, Стив Тейксера и Ксавье Пачеко[1]! И теперь, ничего нам не мешает делать настройки форм в RunTime самым естественным образом, почти так же, как это делает Delphi. А так как мы не можем ориентироваться заранее, какие именно данные вернет нам сервер приложений ООБД, то стала насущной задача сделать интерфейс в полной мере настраиваемым. Итак, задача приложения пользователя состоит в том, чтобы вывести окно авторизации пользователя, попытаться подключиться к серверу приложений, и согласно настройкам, загрузить первый экран из ООБД, так называемое, главное окно. Все остальное должно быть встроено в настройки окна. В том числе и все методы работы с данными, окна справочников и т.д. и т.п. Еще одной задачей приложения пользователя можно считать некий интерфейс задания настроек по умолчанию и показ окна About. Вот собственно и все.

Столь малый круг задач, однако, не говорит о том, что приложение пользователя будет маленьким по размерам, т.к. приложение пользователя должно закомпилировать в себя все классы, которые можно будет использовать в настройках. Чтобы сократить как-то его размер, можно использовать DLL с закомпилированными в них классами, например, BPL от Borland или «самодельные». Способ, при котором все компоненты являются ActiveX, конечно, имеет право на существование, так как позволяет даже подключать дополнительные компоненты, которых нет в стандартной поставке. Однако, не забывайте, что Вы сразу отсекаете пользователей других операционных систем от Ваших программ. Так как эти компоненты специфичны только для MS Windows.

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

Можно, хоть и не нужно все-таки строить приложения пользователя обычным способом, но используя для доступа к ООБД специализированные компоненты, конечно.

Сервер приложений.

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

Кроме того, сервер приложений должен формировать данные, которые естественным образом могут быть помещены в какой-нибудь потомок TdataSet. Он же должен по требованию предоставлять клиентской программе всю информацию о типах и RTTI. На сервере приложений должно быть реализована security. Большим плюсом может стать встроенная буферизация наборов данных. Если строить сервер приложений как Super Server, т.е. один процесс на все клиентские потоки и использовать пул модулей данных, открытие наборов данных в файл, а не в оперативную память, то эта задача вполне может быть решена.  Кроме того, для возможности масштабирования и распределения БД на разные физически серверы, можно организовать стыковку нескольких серверов приложений с помощью COM+ или «самодельными» средствами. Это большой круг не очень сложных и очень рутинных проблем.

Стоит ли использовать MIDAS? Стоит ли использовать COM для связи клиента и сервера приложений? Что COM использовать в чистом виде точно не стоит, следует из того, что в сложной корпоративной сети, с большим количеством серверов и маршрутиризаторов, Вам точно не удастся подключится через COM. Использование MIDAS как основного протокола обмена, например, TsocketConnection и сервиса ScktSrvr.exe выглядит значительно привлекательнее. Но не забывайте, что MIDAS не халява. И Ваш заказчик должен будет выложить некую сумму. Поэтому я все сильнее склоняюсь воспользоваться обычным Socket для реализации обмена по протоколу TCPIP. Т.е. в таком случае сервер приложений будет сервисом, а на клиенте будет лежать специальная DLL для связи с сервером приложений. Такая архитектура позволяет и более безболезненно мигрировать на другие операционные системы.

Роботы.

Роботы – это программы, способные взаимодействовать с ООБД и выполнять какой-нибудь класс действий. Например,  можно сделать робот-печатник, который будет способен распечатывать документы, согласно настройкам, или робот-мигратор, который способен производить расчеты, копирование данных в ООБД. Все эти программы взаимодействуют с ООБД через специальный интерфейс. Если строить этот интерфейс на COM, как это я сейчас и делаю, то достаточно в интерфейсе иметь два метода: Design и Run. Design позволяет сделать настройки, а Run – выполнить действие. Методам передается контекст подключения к ядру и номер записи. Робот может, согласно контексту, подключиться к ядру от имени пользователя, по номеру записи определить её тип и либо выполнить действие, настройки на которое хранятся в ООБД, либо создать эти настройки. Идея создания роботов родилась в процессе создания клиентской программы, т.к. заранее неизвестно что именно пользователь захочет делать с данными. Можно было бы встроить в клиент возможность печати, можно встроить возможность производить расчеты… А если завтра нужно будет отправлять электронные письма? Или управлять внешними устройствами, например, станком с ЧПУ? Поэтому, лучше всего использовать именно отдельное приложение для таких задач. Не нужно делать утку, которая и летает хуже ласточки, и плавает не так хорошо как рыба, и бегает хуже лошади.

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

Оценка производительности [2].

Мне часто задают вопрос о скорости работы УБД. А быстро ли она работает? А подойдет ли она для автоматизации крупного предприятия?

Возьмем «Мир ПК» #4 за 2002 год. На стр. 51 читаем победную новость уважаемой компании о своей замечательной системе: «Предприятие работает с 3 тыс. контрагентов, выпускает около 1 тыс. видов товаров и материалов, ежегодно вводит 20 тыс. операционных документов. Естественно, очень сложно управлять этим хозяйством, не создав единую информационную среду и не построив современную корпоративную систему управления.» Это цитата. Что мы можем здесь почерпнуть? Справочник контрагентов составляет около 3 тыс. строк – это более чем допустимо. Справочник видов товаров и материалов – 1 тыс. строк – мелочь. 20 тыс. операционных документов, разбитых по месяцам, или даже по годам – нет проблем. Если по месяцам, то открытие любого месяца – пара секунд.

 Возьмем бухгалтерию. К примеру, ОАО Novoship. Списочный состав – не более 3.5 тыс. человек в одной компании (а там их много). Единственная кажущаяся непреодолимым препятствием – это база с проводками, которых уйма, и даже больше (наверное, уже больше 1 Гб). Проводки – это закостенелый тип данных. Никаких изменений в них, до самого конца света не будет. Нет, не план счетов, а именно структура, в которой они хранятся. Так что нет проблем – делаем этот тип на основе обычной таблицы и все.

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

Факторы, влияющие на производительность.

Как – то пришло ко мне письмо с вопросом: «Вот, мол, мы пишем свою базу с объектным подходом, но, если в базе более 1000 строк, то начинаются жуткие тормоза. А как у Вас?». Я быстро ответил, что и у меня при увеличении количества строк, тоже, начинаются тормоза. Отослал и пожалел, что так быстро. Может, люди создали нечто, что в базе начинаются проблемы после 1000 строк? В УБД размер базы не критичен, по крайней мере, не более, чем для обычных программ, написанных обычными методами. Собственно, Вы можете убедиться, что «сборка» данных запросом производится, исключительно используя оптимальные планы, и ведется, используя первичные ключи. Никаких натуральных переборов. На самом деле, критичным является единовременная выборка большого количества строк при открытии документа. На данном этапе дела обстоят примерно так: если сервером выступает AMD Athlon 1000, с обычным IDE диском, 256 Мб памяти. УБД сервер и InterBase на одном компьютере. Сетка 100 Мб, а клиентом – PIII 500, 256 Мб памяти, то Fech чуть более 20 000 строк с 15 столбиками разного типа: целые числа, даты, строки и т.д. происходит менее чем за 10 секунд. Так же, не влияет на производительность глубина наследования, и количество типов данных в справочнике типов.  И это при том, что я не самый лучший программист в мире, и уже нашел места в программе, которые в следующих версиях будут оптимизированы, а значит производительность еще немного подрастет.

Заключение.

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

По мере укрепления рынка ООБД, будут создаваться группы поддержки, которые будут заниматься только продажей и поддержкой настроек. В этой области важно создать простой механизм импорта / экспорта настроек. Я думаю, что для этого лучше всего использовать общепризнанные средства, поддерживающие распространенные стандарты описания объектной модели, такие как  Rational Rouse или Visio. Поэтому возрастет актуальность повсеместного применения UML как средства хранения описаний объектов, интерфейсов и программных комплексов в целом. Эти же средства можно будет применять для оценки качества ПО.

Глоссарий.

ActiveX            - Компонентная модель Microsoft, основанная на COM.

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

CASE              - Средство визуального моделирования и проектирования.

COM               - Компонентная модель объектов – технология Microsoft, реализующая интерфейсный подход работы с объектами.

COM+                        - Расширение COM для построения многозвенных комплексов, в том числе и баз данных.

MIDAS            - Технология Borland для построения многозвенных комплексов баз данных.

RAD                - Среда быстрой разработки программ.

RTTI                - Информация времени выполнения, т.е. информация, доступная во время выполнения, например, программы.

Security            - Правила построения системы безопасности.

SQL                - Язык структурированных запросов. Применяется для работы с серверами БД.

TCPIP             - Протокол обмена в сети.

UML               - Универсальный язык описания объектов.

БД                   - База данных.

ПО                  - Программное обеспечение.

ЧПУ                - Числовое программное управление. Часто применяется при описании станков с числовым программным управлением.

 

 

 



[1] Авторы популярного издания «Delphi 6 Руководство разработчика».

[2] Эта часть статьи основана на опыте разработки объектно-ориентированной БД. Мой проект я называю УБД, т.е. «Универсальная База Данных».

 

    Банников Н.А. www.stikriz.narod.ru почта 2003 г.

Сайт создан в системе uCoz