RSS    

Видеокурсы

Видеокурсы по ВТ

Опасности в социальных сетях

Социальные сети

Программы для бесплатного просмотра online tv...  

Компьютер заражен? Есть несколько вариантов вылечить ПК...

Стандарт LTE - Long-Term Evolution - или стандарт связи четвертого поколения (4G) считается перспективным... 



Базы данных: ORM или ДОБД?

technology-marketing-i151Человечество тысячи лет ищет лучшие способы систематизировать информацию за счет создания описаний объектов в базах данных.

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

Я с уважением отношусь к глиняным дощечкам и реляционным базам данных (РБД), но при проектировании сложных систем нужны технологии, ориентированные на описание объектов: такие как ORM (объектно-реляционное отображение) и ДОБД (документоориентированная база данных).
К сожалению, мировое общественное мнение этого пока не понимает, и во всем мире плодятся системы на основе реляционных таблиц, глядя на которые хочется сказать:
«Лучше бы он прогулял лекции по РБД».

 

ORM или ДОБД

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

 

  • При наследовании класса в дополнении к таблице базового класса создается дополнительная таблица. Объект расползается по двум (или более) таблицам.
  • Пустые атрибуты объекта все равно присутствуют в базе.
  • Добавление атрибутов в описание класса требует изменения структуры БД.
  • Удаление атрибутов из описания класса невозможно, т.к. вызовет потерю информации в БД.
  • Невозможно использовать внешние программные модули, которые могли бы добавить к существующему объекту свои собственные атрибуты.

 

Более гибким инструментом является ДОБД. Единственный его недостаток – это неудачное название. Программисты ничего не понимают в документах и страшное слово их пугает. В данном случае документ – это набор атрибутов конкретного объекта, имеющего уникальный идентификатор (UNID - уникальный идентификатор (он же UUID, он же GUID)). Атрибуты хранятся в виде ключ:значение.
Ключ – это название поля, в качестве значения может быть строка или JSON-строка (хотя, пользы от JSON мало, а обработка сложнее).
Ссылки на справочники запрещены – объект после создания должен быть самодостаточен и не должен зависеть от других таблиц. Единственные разрешенные ссылки – это ссылки на другие объекты (документы) и на файлы.
Ссылки на объекты представляют собой иерархический путь к хранилищу объектов и UNID объекта.
Ссылки на файлы – это атрибуты файла и UNID файла. Сам файл может храниться в таблице блобов (blob – двоичный большой объект) или в файловой системе.

 

Стереотипы поведения и навыки адаптации объектов в ДОБД

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

  • beforeOpen — Для нового документа заполнение полей по умолчанию, для любого документа заполнение вычисляемых полей.
  • beforeSave — Обработка документа перед сохранением.
  • afterSave — Действия с базой после сохранения документа.

На клиенте тоже ничего нового:

  • postOpenDoc – дополнительная инициализация экранной формы (используется редко).
  • setAndVerify(true, false) – Заполняет вычисляемые поля экранной формы перед сохранением.
  • setAndVerify(false, true) – Проверяет значения полей экранной формы перед сохранением.
  • setAndVerify(true, true) – и то, и другое.

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

Примеры правил (правило - это атрибут объекта, например 'linkRule':'clerk')

  • groundRule – правило описывает создание нового объекта на основании существующего.
  • linkRule – объект может ссылаться на другие объекты. Данное правило описывает действия со связанными объектами при сохранении основного.
  • viewRule – правило описывает формирование html-разметки при отображении объектов в виде списка.

В нашем случае внешние обработчики – это скрипты на Python 3.3 или JS, которые хранятся в базе данных в виде текста.

 

ДОБД на SQL

Я не люблю РБД, но это не значит, что я не люблю SQL-серверы. Я снимаю шляпу перед разработчиками, посвятившим свои жизни оптимизации SQL-серверов, и ни в коем случае не хочу от SQL отказываться.
Мы тестировали нашу систему на журнале из 1 000 000 документов на SQLite3, MySQL, PostgreSQL. SQLite3 - тормоз, MySQL и PostgreSQL работают великолепно и по скорости одинаковы.
При всем уважении к MongoDB, брать ее за основу мы не рискнули и правильно сделали. По мере ее распространения появляется все больше критики и в части быстродействия, и в части функциональности, не говоря уже о сложностях интеграции с существующими системами. Все чаще я встречаю статьи (почему-то исключительно импортные) о том, что выбрав MongoDB и сделав на ней систему, разработчики вынуждены от нее отказаться и вернуться к SQL-серверам.
Кроме того она не совсем бесплатная: подписка на MongoDB стоит для граждан США $7500. А я не гражданин США. А если вдруг санкции?

Короче, мы сделали ДОБД на основе SQL-таблицы. Сделать это оказалось не просто, а очень просто.
Вся информация об объектах хранится в таблице из 5 столбцов:

unid xcrt xnam xval xmdf
binary(16) timestamp text(32) text(65000) timestamp
UUID момент создания записи имя поля значение поля момент перевода записи в историю

Столбец "xmdf" совместно с атрибутом "MODIFIER" позволяет отследить, кто когда какие поля правил.

Для загрузки документа в классе Database имеется соответствующий метод:

def getDocumentByUNID(self, unid):
    sql = "SELECT xnam, xval, xcrt FROM {0} WHERE (unid = {1}) AND (xmdf IS NULL)".format(self.dbTable, unid)
    ...

Сие означает, что мы хотим получить для документа, имеющего вот такой вот unid, список всех актуальных (xmdf IS NULL) полей с их значениями и датой создания.

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

 

А что в википедии?

Автор статьи о ДОБД в википедии уподобил документоориентированную БД лесу, в котором деревья покрываются сучьями, а те обрастают листиками. Странно, что он использовал термин "коллекции", а не "гербарии".
При этом автор смешал такие понятия, как ДОБД и реализованный в MongoDB NoSQL, хотя ДОБД появились в прошлом веке, когда монго еще висел на пальме в виде фрукта, а пользователи наслаждались цветочками Лотуса по $100 за штуку. Ныне покойный Lotus Notes конечно SQL'ем не назовешь, но никаких листиков на сучьях там не было.

 

Мы положили в основу документоориентированной БД множество несвязанных SQL-таблиц (журналов) и доменный принцип построения системы: просто, понятно, гибко,
легко описывается, легко администрируется, легко масштабируется.

 

Чтобы не путать с интернетом, домен пишем слева направо:
RF.TVR.MF - министерство финансов Тверской области РФ.
RF.TVR.MO - министерство образования Тверской области РФ.

 

Алиас журнала формируется из домена, префикса журнала и года:
RF.TVR.MF/DP_2014 - журнал "Входящие 2014" Минфина ТО

 

Имя SQL-таблицы формируется из алиаса: RF_TVR_MF_DP_2014

Ссылки на документы состоят из алиаса журнала и UNID'а документа:
RF.TVR.MF/DP_2014&BABAD9A62B0B5A1016627D7FC005F176

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

 

Выглядит это примерно так:
...
# doc - исходный объект, многозначное поле links содержит ссылки
if doc.links: # проверяем, есть ли непустое поле со ссылками
    link = doc.A('links')[0] # берем первую ссылку
    dbAlias, unid = link.split('&') # расщепить ссылку на алиас и UNID
    db = getDB(dbAlias) # установить коннекцию к журналу
    linkedDoc = db.getDocumentByUNID(unid) # загрузить связанный документ
...

 

Иерархия документов в журнале

В течение жизненного цикла документ как правило обрастает историей. Хранить историю внутри объекта некрасиво и неправильно. Разумно разрешить документу иметь в том же журнале подчиненные документы (с точки зрения пользователя "подчиненные записи"). Реализуется это элементарно: добавляем в подчиненный объект поле REF, содержащее UNID родительского документа, а для визуализации в списке документов рядом с главным документом рисуем треугольник ▼ или ► (скрыть или показать историю).

 

Для программиста все тоже просто: метод getDocWithResponses(unid)возвращает коллекцию из главного документа и всех подчиненных.
Обработчики событий подчиненных документов могут изменять главный документ. Для этих целей предусмотрен свой набор правил: responsRule.


Тем, кого заинтересовала описанная технология, я рекомендую скачать бесплатную CRM-Sova и с помощью SQLite-смотрелки исследовать базы. В Сове нет никаких ограничений и вредоносных закладок, это рекламная акция для популяризации фреймворка. 

 

Материал предоставлен Носиковым А.О.,  Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript

 

 

 

Оставьте свой отзыв:

Добавить комментарий


Защитный код
Обновить

 

Самое читаемое:

Быстрый поиск

Группа вКонтакте: новости

 

Новости в Twitter и Facebook

  подписка на новости в twitter              Подписка на новости facebook

Инструкции к программам

Инструкции к программам

Новые информационные технологии и программы