Съвременните информационни системи са доста сложни. Не на последно място, тяхната сложност се дължи на сложността на обработваните данни. Сложността на данните често е свързана с многообразието на използваните модели на данни. Например, когато данните станат „големи“, една от характеристиките, която създава неудобство, е не само техният обем („volume“), но и тяхното разнообразие („variety“).
Ако все още не намирате недостатък в разсъжденията, прочетете нататък.

Съдържание
Polyglot persistence
Горното води до това, че понякога в рамките на дори една система е необходимо да се използват няколко различни СУБД за съхранение на данни и решаване на различни задачи за тяхната обработка, като всяка от тях поддържа свой собствен модел на данни. По инициатива на М. Фаулера, броя известни книги и един от Agile Manifesto, тази ситуация получи името многовариантно хранилище („polyglot persistence“).
Фаулеру принадлежи и следния пример за организация на съхранение на данни в многофункционално и високо натоварено приложение в сферата на електронната търговия.

Този пример е разбираемо малко преувеличен, но някои съображения в полза на избора на съответната СУБД за определена цел могат да бъдат намерени, например, .
Ясно е, че е трудно да си служител в такава зоологическа градина.
- Обемът на кода, който изпълнява запазването на данни, нараства пропорционално на броя на използваните СУБД; обемът на кода, синхронизиращ данните, - добре е, ако не е пропорционален на квадрата на това число.
- Разходите за осигуряване на enterprise-характеристиките (скалируемост, устойчивост на повреди, висока достъпност) на всяка от използваните СУБД нарастват кратно на броя на използваните СУБД.
- Невъзможно е да се осигурят enterprise-характеристики на подсистемата за съхранение като цяло - особено транзакционност.
От гледна точка на директора на зоологическата градина, всичко изглежда така:
- Кратно увеличаване на разходите за лицензи и техническа поддръжка от производителя на СУБД.
- Увеличаване на щата и удължаване на сроковете.
- Преки финансови загуби или санкции поради несъответствия в данните.
Има значителен ръст в общата стойност на притежание на системата (TCO). Има ли изход от ситуацията с 'многовариантно съхранение'?
Мултимоделност
Терминът 'многовариантно съхранение' стана популярен през 2011 година. Осъзнаването на проблемите с този подход и търсенето на решение отне няколко години, а до 2015 година аналитиците от Gartner формулираха отговора:
- От '»:
Бъдещето на СУБД, техните архитектури и начини на употреба — многомоделност.
- От '»:
Водещите оперативни СУБД ще предлагат няколко модела — релационен и нерелационни — в рамките на една единствена платформа.
Изглежда, че този път аналитиците от Gartner не сбъркаха с прогнозата си. Ако посетите страницата с СУБД на DB-Engines, можете да видите, че боольшата част от неговите лидери се позиционират именно като многомоделни СУБД. Същото може да се види и на страницата с всеки частен рейтинг.
В таблицата по-долу са представени СУБД — лидери в всеки от частните рейтинги, които заявяват своята многомоделност. За всяка СУБД са посочени първоначално поддържаната модел (когато е била единствена) и заедно с нея моделите, които се поддържат в момента. Представени са също и СУБД, които се позиционират като 'първоначално многомоделни', без наличието на каквато и да е първоначална наследена модел според твърденията на създателите им.
| СУБД | Първоначален модел | Допълнителни модели |
|---|---|---|
| Oracle | Релационна | Графов, документен |
| MS SQL | Релационна | Графов, документен |
| PostgreSQL | Релационна | Графов*, документен |
| MarkLogic | Документен | Графов, релационен |
| MongoDB | Документен | Ключ-стойност, графов* |
| DataStax | Широк колона | Документен, графов |
| Redis | Ключ-стойност | Документен, графов* |
| ArangoDB | — | Графов, документен |
| OrientDB | — | Графов, документен, релационен |
| Azure CosmosDB | — | Графов, документен, релационен |
Забележки към таблицата
С звездичките в таблицата са маркирани твърдения, изискващи уговорки:
- СУБД PostgreSQL не поддържа графова модел на данни, но такъв продукт , като например, AgensGraph.
- Относно MongoDB е по-правилно да се говори по-скоро за наличието на графови оператори в езика за заявки (, ), отколкото за поддръжка на графовата модел, въпреки че, разбира се, тяхното въвеждане изискваше някои оптимизации на физическото съхранение в посока на поддръжка на графовата модел.
- Относно Redis се има предвид разширение .
Нататък ще покажем как за всеки от класовете се реализира поддръжка на различни модели в базите данни от този клас. Най-важни ще считаме релационния, документния и графовия модели, като на примери от конкретни СУБД ще демонстрираме как се реализират "недостигналите".
Мултимоделни СУБД, основани на релационен модел
Водещите СУБД в момента са релационните, предвиждането на Gartner не би могло да се счита за сбъднато, ако РСУБД не демонстрираха напредък в посока мултимоделност. И те наистина демонстрират. Сега забележките, че мултимоделната СУБД е като швейцарски нож, с който не може да се направи нищо добре, могат да бъдат адресирани директно на Лари Елисън.
Авторът обаче предпочита реализацията на мултимоделността в Microsoft SQL Server, на примера на който ще бъде описана поддръжката на релационни СУБД за документни и графови модели.
Документен модел в MS SQL Server
За това как в MS SQL Server е реализирана поддръжка на документния модел, вече имаше две отлични статии в Хабра, затова ще се ограничим до кратко резюме и коментар:
Методът за поддръжка на документния модел в MS SQL Server е доста типичен за релационни СУБД: предлагат се JSON-документи да се съхраняват в обикновени текстови полета. Поддръжката на документния модел включва предоставянето на специални оператори за обработка на този JSON:
- за извличане на скалярни стойности от атрибути,
- за извличане на поддокументи.
Вторият аргумент на двата оператора е израз в синтаксис, наподобяващ JSONPath.
Абстрактно може да се твърди, че съхраняваните по този начин документи не са "първокласни сущности" в релационната СУБД, в противовес на кортежите. Конкретно в MS SQL Server в момента липсват индекси по полетата на JSON-документите, което затруднява операцията по свързване на таблиците по стойностите на тези полета и дори извличането на документи по тези стойности. Въпреки това, е възможно да се създаде изчисляем стълб по такова поле и индекс по него.
Допълнително, MS SQL Server предоставя възможността удобно да се конструира JSON-документ от съдържанието на таблиците с помощта на оператора — възможност, в известен смисъл противоположна на предишната, обичайното съхранение. Ясно е, че каквато и да е бързината на РСУБД, такъв подход противоречи на идеологията на документните СУБД, които по същество съхраняват готови отговори на популярни запитвания и могат да решават само проблеми с удобството на разработката, но не и с бързодействието.
Накрая, MS SQL Server позволява да се реши задачата, противоположна на създаването на документ: можете да разпределите JSON по таблици с помощта на . Ако документът не е напълно плосък, ще е необходимо да се използва PIVOT.
Графов модел в MS SQL Server
Поддръжката на графовата (LPG) модел е реализирана в Microsoft SQL Server също напълно : предлагат се специални таблици за съхранение на възли и за съхранение на ребра на графа. Такива таблици се създават с помощта на изрази CREATE TABLE AS NODE и CREATE TABLE AS EDGE съответно.
Таблиците от първия вид са сходни с обикновените таблици за съхранение на записи, с единственото външно отличие, че в таблицата присъства системно поле $node_id — уникален в рамките на базата данни идентификатор на възела на графа.
Аналогично, таблиците от втория вид имат системни полета $from_id и $to_id, записите в такива таблици очевидно задават връзките между възлите. За съхранение на връзките от всеки вид се използва отделна таблица.
Нека илюстрираме казаното с пример. Нека графовите данни имат схема, каквато е показана на дадената рисунка. Тогава за създаване на съответната структура в базата данни е необходимо да се изпълнят следните DDL-заявки:
CREATE TABLE Person (
ID INTEGER NOT NULL,
name VARCHAR(100)
) AS NODE;
CREATE TABLE Cafe (
ID INTEGER NOT NULL,
name VARCHAR(100),
) AS NODE;
CREATE TABLE likes (
rating INTEGER
) AS EDGE;
CREATE TABLE friendOf
AS EDGE;
ALTER TABLE likes
ADD CONSTRAINT EC_LIKES CONNECTION (Person TO Cafe);Основната специфика на такива таблици е, че в запитванията към тях е възможно да се използват графови шаблони със синтаксис, подобен на Cypher (обаче "*" и пр. все още не се поддържат). На базата на измерванията на производителността също може да се предположи, че начинът на съхранение на данните в тези таблици е различен от механизма за съхранение на данни в обикновените таблици и е оптимизиран за изпълнение на подобни графови запитвания.
SELECT Cafe.name
FROM Person, likes, Cafe
WHERE MATCH (Person-(friendOf)-(likes)->Cafe)
AND Person.name = 'John';Освен това, доста трудно е при работа с такива таблици да не се използват тези графови модели, тъй като в обикновените SQL заявки за решаване на аналогични задачи ще са необходими допълнителни усилия за получаване на системни „графови“ идентификатори на възлите ($node_id, $from_id, $to_id; по същата причина заявките за вмъкване на данни не са предоставени тук, тъй като биха били прекалено обемисти).
В заключение на описанието на реализациите на документната и графовата модели в MS SQL Server, бих отбелязал, че подобни реализации на една модел върху друг не изглеждат успешни преди всичко от гледна точка на езиковия дизайн. Необходимо е да се разширява един език с друг, езиците не са напълно „ортогонални“, а правилата за съвместимост могат да бъдат доста странни.
Мултимоделни СУБД на основата на документен модел
В този раздел искам да илюстрирам реализацията на мултимоделност в документни СУБД, използвайки примера на не най-популярната от тях MongoDB (както бе споменато, в нея има само условно графови оператори $lookup и $graphLookup, които не работят на шардированные колекции), а на примера на по-зряла и „ентърпрайз“ СУБД .
И така, нека колекцията съдържа набор от XML-документи от следния вид (съхраняването на JSON-документи също е възможно в MarkLogic):
Джон
СмитРелационен модел в MarkLogic
Релационното представяне на колекцията от документи може да бъде създадено с помощта на (съдържанието на елементите стойност в примера по-долу може да бъде произволен XPath):
/Person
Person
SSN
@SSN
string
name
name
surname
surnameК създаденото представяне може да се адресира SQL заявка (например, чрез ODBC):
SELECT name, surname FROM Person WHERE name="Джон"За съжаление, създаденото с помощта на шаблона за отстраняване релационно представяне е само за четене. При обработка на заявка към него MarkLogic ще се опита да използва . Преди в MarkLogic имаше и ограничени релационни представяния, изцяло и достъпни за запис, но в момента те се считат за deprecated.
Графов модел в MarkLogic
С подкрепата на графовата (RDF) модел всичко стои приблизително по същия начин. Отново с помощта на може да се създаде RDF-представление на колекция от документи от примера по-горе:
/Person
PREFIX
"http://example.org/example#"
sem:iri( $PREFIX || @SSN )
sem:iri( $PREFIX || surname )
sem:iri( $PREFIX || @SSN )
sem:iri( $PREFIX || name )
Към получения RDF-граф може да се адресира SPARQL-запитване:
PREFIX :
SELECT ?name ?surname {
:631803299804 :name ?name ; :surname ?surname .
}В отличие от релационната, графовата модел MarkLogic поддържа още по два други начина:
- СУБД може да бъде напълно отделно хранилище за RDF-данни (триплетите в него ще се наричат в контекста на описаното по-горе ).
- RDF в специална сериализация може просто да бъде вмъкнат в XML- или JSON-документи (и триплетите тогава ще се наричат ). Вероятно, това е такава алтернатива на механизмите
idrefи пр.
Добра представа за това как "наистина" всичко е устроено в MarkLogic дава , в този смисъл той е нискоуровневен, въпреки че предназначението му е по-скоро противоположно — да опита да абстрахира от използвания модел на данни, да осигури последователна работа с данни в различни модели, транзакционност и пр.
Мултимоделни СУБД „без основен модел“
На пазара също са представени СУБД, позициониращи се като изначално многомоделни, без никаква наследена основна модел. Към тях се числят , (от 2018 г. компанията-разработчик принадлежи на SAP) и (услуга в рамките на облачната платформа Microsoft Azure).
Всъщност "основни" модели в ArangoDB и OrientDB съществуват. Това в случая и в двата случая са собствени модели на данни, които представляват обобщения на документната. Обобщенията се състоят основно в улесняването на възможността за извършване на запитвания с графов и релационен характер.
Тези модели са единствено достъпни за използване в посочените СУБД, а за работа с тях са предназначени собствени езици за заявки. Безспорно, такива модели и СУБД са перспективни, но липсата на съвместимост със стандартните модели и езици прави невъзможно използването на тези СУБД в наследените системи — тяхната замяна с вече използвани СУБД е недопустима.
За ArangoDB и OrientDB в Хабра вече имаше страхотна статия: .
ArangoDB
ArangoDB обявява поддръжка на графовата модел на данни.
Връзките в графа в ArangoDB са обикновени документи, а ребрата — документи от специален вид, които имат наред с обикновените системни полета (_key, _id, _rev) системни полета _from и _to. Документите в документните СУБД традиционно се обединяват в колекции. Колекциите на документите, представляващи ребрата, в ArangoDB се наричат edge-колекции. Между другото, документите на edge-колекциите също са документи, така че ребрата в ArangoDB могат да изпълняват ролята и на възли.
Изходни данни
Нека да имаме колекция persons, документите на която изглеждат така:
[
{
"_id" : "people/alice" ,
"_key" : "alice" ,
"name" : "Алиса"
},
{
"_id" : "people/bob" ,
"_key" : "bob" ,
"name" : "Боб"
}
]Нека също така имаме колекция cafes:
[
{
"_id" : "cafes/jd" ,
"_key" : "jd" ,
"name" : "Джон Донн"
},
{
"_id" : "cafes/jj" ,
"_key" : "jj" ,
"name" : "Жан-Жак"
}
]Тогава колекцията likes може да изглежда по следния начин:
[
{
"_id" : "likes/1" ,
"_key" : "1" ,
"_from" : "persons/alice" ,
"_to" : "cafes/jd",
"since" : 2010
},
{
"_id" : "likes/2" ,
"_key" : "2" ,
"_from" : "persons/alice" ,
"_to" : "cafes/jj",
"since" : 2011
} ,
{
"_id" : "likes/3" ,
"_key" : "3" ,
"_from" : "persons/bob" ,
"_to" : "cafes/jd",
"since" : 2012
}
]Запросите и резултати
Запит в графов стил на използвания в ArangoDB език AQL, който връща в човекочитаем вид информация за това, на кого какво кафе му харесва, изглежда така:
FOR p IN persons
FOR c IN OUTBOUND p likes
RETURN { person : p.name , likes : c.name }В релационен стил, когато по-скоро „изчисляваме“ връзките, вместо да ги съхраняваме, този запит може да бъде преписан така (между другото, без колекция likes можеше да се мине и без нея):
FOR p IN persons
FOR l IN likes
FILTER p._key == l._from
FOR c IN cafes
FILTER l._to == c._key
RETURN { person : p.name , likes : c.name }Резултатът и в двата случая ще бъде един и същ:
[
{ "person" : "Алиса" , likes : "Жан-Жак" } ,
{ "person" : "Алиса" , likes : "Джон Донн" } ,
{ "person" : "Боб" , likes : "Джон Донн" }
]Още запити и резултати
Ако изглежда, че формата на резултата по-горе е характерен повече за релационна СУБД, отколкото за документна, можете да опитате следния запит (или можете да се възползвате от ):
FOR p IN persons
RETURN {
person : p.name,
likes : (
FOR c IN OUTBOUND p likes
RETURN c.name
)
}Резултатът ще има следния вид:
[
{ "person" : "Алиса" , likes : ["Жан-Жак" , "Джон Донн"] } ,
{ "person" : "Боб" , likes : ["Джон Донн"] }
]OrientDB
В основата на реализирането на графовата модел над документната в OrientDB лежи полета на документите да имат освен по-или по-малко стандартни скаларни стойности също и стойности на такива типове, като ВРЪЗКА, СПИСЪК С ВРЪЗКИ, МНОЖЕСТВО ОТ ВРЪЗКИ, КАРТА С ВРЪЗКИ и КУТИЯ С ВРЪЗКИ. Стойностите на тези типове — връзки или колекции от връзки на документи.
Присвояваният от системата идентификатор на документа има "физически смисъл", указвайки позицията на записа в базата, и изглежда приблизително така: @rid : #3:16. Така стойностите на референтните свойства — всъщност по-скоро указатели (както в графовата модел), а не условия за отбор (както в релационната).
Подобно на ArangoDB, в OrientDB ребрата се представят като отделни документи (въпреки че, ако реброто няма собствени свойства, може да бъде , и няма да му отговаря отделен документ).
Изходни данни
В формат, близък до базата OrientDB, данните от предишния пример за ArangoDB биха изглеждали по следния начин:
[
{
"@type": "document",
"@rid": "#11:0",
"@class": "Person",
"name": "Алиса",
"out_likes": [
"#30:1",
"#30:2"
],
"@fieldTypes": "out_likes=LINKBAG"
},
{
"@type": "document",
"@rid": "#12:0",
"@class": "Person",
"name": "Боб",
"out_likes": [
"#30:3"
],
"@fieldTypes": "out_likes=LINKBAG"
},
{
"@type": "document",
"@rid": "#21:0",
"@class": "Cafe",
"name": "Жан-Жак",
"in_likes": [
"#30:2",
"#30:3"
],
"@fieldTypes": "in_likes=LINKBAG"
},
{
"@type": "document",
"@rid": "#22:0",
"@class": "Cafe",
"name": "Джон Донн",
"in_likes": [
"#30:1"
],
"@fieldTypes": "in_likes=LINKBAG"
},
{
"@type": "document",
"@rid": "#30:1",
"@class": "likes",
"in": "#22:0",
"out": "#11:0",
"since": 1262286000000,
"@fieldTypes": "in=LINK,out=LINK,since=date"
},
{
"@type": "document",
"@rid": "#30:2",
"@class": "likes",
"in": "#21:0",
"out": "#11:0",
"since": 1293822000000,
"@fieldTypes": "in=LINK,out=LINK,since=date"
},
{
"@type": "document",
"@rid": "#30:3",
"@class": "likes",
"in": "#21:0",
"out": "#12:0",
"since": 1325354400000,
"@fieldTypes": "in=LINK,out=LINK,since=date"
}
]Както виждаме, върховете също съхраняват информация за входящите и изходящите ребра. При API документ за интегритет на връзките е нужно да следите самостоятелно, а Graph API поема тази работа. Нека видим как изглежда заявката към OrientDB на "чисти", неинтегрирани в езиците за програмиране, езици за заявки.
Запросите и резултати
Заявката, аналогична на предназначението на заявката от примера за ArangoDB, в OrientDB изглежда така:
SELECT name AS person_name, OUT('likes').name AS cafe_name
FROM Person
UNWIND cafe_nameРезултатът ще бъде получен в следния вид:
[
{ "person_name": "Алиса", "cafe_name": "Джон Донн" },
{ "person_name": "Алиса", "cafe_name": "Жан-Жак" },
{ "person_name": "Боб", "cafe_name": "Жан-Жак" }
]Ако форматът на резултата отново изглежда прекалено "релационен", трябва да се премахне редът с :
[
{ "person_name": "Алиса", "cafe_name": [ "Джон Донн", "Жан-Жак" ] },
{ "person_name": "Боб", "cafe_name": [ "Жан-Жак" ] }
]Езикът за заявки на OrientDB може да бъде описан като SQL с Gremlin-подобни вмъквания. В версия 2.2 се появи форма на заявка, подобна на Cypher, :
MATCH {CLASS: Person, AS: person}-likes->{CLASS: Cafe, AS: cafe}
RETURN person.name AS person_name, LIST(cafe.name) AS cafe_name
GROUP BY person_nameФорматът на резултата ще бъде същият, както в предишната заявка. Помислете какво трябва да се премахне, за да го направи по "релационен", както в самата първа заявка.
Azure CosmosDB
В по-малка степен казаното по-горе за ArangoDB и OrientDB се отнася за Azure CosmosDB. CosmosDB предоставя следните API за достъп до данни: SQL, MongoDB, Gremlin и Cassandra.
SQL API и MongoDB API се използват за достъп до данни в документни модели. Gremlin API и Cassandra API — за достъп до данни съответно в графови и колонкови модели. Данните в всички модели се съхраняват във формата на вътрешна модел на CosmosDB: („atom-record-sequence“), който също е близък до документния модел.

Но избраната от потребителя модел на данни и използваният API се фиксират в момента на създаването на акаунта в услугата. Невъзможно е да получите достъп до данни, качени в една модел, в формат на друга модел, което би било илюстрирано по следния начин:

Така мултиподобността в Azure CosmosDB към днешна дата представлява само възможността да се използват няколко бази данни, поддържащи различни модели, от един производител, което не решава всички проблеми на многовариантното съхранение.
Мултимоделни СУБД, основани на графов модел?
Прави впечатление фактът, че на пазара все още няма мултиподобни СУБД, които имат основа графов модел (освен ако не се счита за мултиподобност поддръжката на едновременно две графови модела: RDF и LPG; вижте за това в ). Най-голямо затруднение представлява реализирането на документна модель върху графова структура, а не релационна.
Въпросът как да се реализира релационна структура върху графова модел е разглеждан още в началния период на тази последната. Как , например, :
В графовия подход няма нищо, което да попречи на създаването на слой (например, чрез подходящо индексиране) върху графова база данни, който позволява релационен изглед с (1) извличане на двойки от обичайните ключови стойности и (2) групиране на двойки по тип отношение.
При реализиране на документната модел върху графова структура е необходимо да се имат предвид, например, следните аспекти:
- Елементите на JSON масива се считат за подредени, но изходящите от върха на реброто на графа не са;
- Данните в документната модел обикновено са денормализирани, не желаем да съхраняваме няколко копия на един и същ вложен документ, и обикновено поддокументите нямат идентификатори;
- От друга страна, идеологията на документните СУБД е, че документите са готови "агрегати", които не трябва да се изграждат отново всеки път. Необходимо е да се осигури в графовата модел възможност за бързо получаване на подграф, отговарящ на готов документ.
Малко реклама
Авторът на статията има отношение към разработката на СУБД NitrosBase, чиято вътрешна модел е графова, а външните модели — релационна и документна — са нейните представяния. Всички модели са равноправни: практически всякакви данни са достъпни във всяка от тях, използвайки естествения за тях език за запитвания. Освен това, във всяко представяне данните могат да бъдат променяни. Промените ще се отразят във вътрешната модел и съответно в другите представяния.
Как изглежда съответствието на моделите в NitrosBase — ще опиша, надявам се, в една от следващите статии.
Заключение
Надявам се, че общите контури на това, което се нарича многомоделност, станаха по-малко ясни за читателя. Многомоделни СУБД са достатъчно различни и "поддръжката на множество модели" може да изглежда по различен начин. За да се разбере какво се нарича "многомоделност" в конкретния случай, полезно е да се отговори на следните въпроси:
- Става ли въпрос за поддръжка на традиционни модели или за някаква „хибридна“ модел?
- "Равноправни" ли са моделите, или едната от тях е подчинена на другите?
- «Безразлични» ли са моделите един към друг? Могат ли данните, записани в един модел, да бъдат прочетени в друг или дори записани отново?
Мисля, че на въпроса за актуалността на мултимоделните СУБД вече можем да дадем положителен отговор, но интересен е въпросът кои точно техни разновидности ще бъдат по-търсени в близко бъдеще. Изглежда, че по-търсени ще бъдат мултимоделните СУБД, които поддържат традиционни модели, предимно релационен; популярността на мултимоделните СУБД, предлагащи нови модели, съчетаващи предимствата на различни традиционни, остава въпрос на по-далечното бъдеще.
Само регистрирани потребители могат да участват в анкетата. , моля.
Използвате ли мултимоделни СУБД?
Не използваме, съхраняваме всичко в една СУБД и в един модел
Използваме мултимоделни възможности на традиционни СУБД
Практикуваме многовариантно съхранение (polyglot persistence)
Използваме нови мултимоделни СУБД (Arango, Orient, CosmosDB)
Гласували 19 потребители. Въздържали се 4 потребителя.
Източник: habr.com
