現代資訊系統相當複雜。最重要的是,它們的複雜性是由於它們處理的資料的複雜性所造成的。資料的複雜性通常在於所使用的資料模型的多樣性。因此,舉例來說,當資料變得「大」時,有問題的特徵之一不僅是其數量(「volume」),而且是其多樣性(「variety」)。
如果您還沒有發現推理中的缺陷,請繼續閱讀。

Содержание
多語言持久性
上述導致了這樣一個事實:有時即使在一個系統的框架內,也需要使用多個不同的DBMS來儲存資料並解決處理資料的各種問題,每個DBMS都支援自己的資料模型。憑藉 M. Fowler 的輕手, 一些著名的書籍和一本 敏捷宣言,這種情況稱為 多變量存儲 (“多語言持久性”)。
Fowler還有以下在電子商務領域的功能齊全、高負載的應用程式中組織資料儲存的例子。

當然,這個例子有些誇張,但可以找到一些有利於為相應目的選擇一個或另一個 DBMS 的考慮因素,例如, .
顯然,在這樣的動物園裡當僕人並不容易。
- 執行資料儲存的代碼量與所使用的 DBMS 數量成比例增長;如果不與該數字的平方成正比,則同步資料的程式碼量就很好。
- 隨著所使用的 DBMS 數量的倍數增加,為所使用的每個 DBMS 提供企業特性(可擴展性、容錯性、高可用性)的成本也會增加。
- 無法保證整個儲存子系統的企業特性-尤其是事務性。
從動物園園長的角度來看,一切都是這樣的:
- DBMS 製造商的授權和技術支援成本倍增。
- 人員過剩和期限延長。
- 因數據不一致而造成的直接經濟損失或處罰。
系統的總擁有成本 (TCO) 顯著增加。有沒有辦法擺脫「多種儲存選擇」的局面呢?
多重型號
「多元儲存」一詞於 2011 年開始使用。意識到方法的問題並尋找解決方案花了幾年的時間,到 2015 年,透過 Gartner 分析師的口,給出了答案:
- 從 ”»:
DBMS 及其架構和使用方式的未來是多模型的。
- 從 ”»:
領先的營運 DBMS 將提供多種模型(關係型和非關係型)作為單一平台的一部分。
看來這次 Gartner 分析師的預測是正確的。如果您轉到頁面 DB-Engines 上的 DBMS,您可以看到о大多數領導者將自己明確定位為多模式 DBMS。在任何私人評級的頁面上都可以看到相同的情況。
下表顯示了 DBMS - 每個私人評級中的領先者,聲稱是多模型的。對於每個 DBMS,都會指示原始支援的模型(曾經是唯一的模型)以及目前支援的模型。還列出了將自己定位為「原始多模型」的 DBMS,並且根據創建者的說法,沒有任何初始繼承模型。
| 數據庫管理系統 | 初始模型 | 附加型號 |
|---|---|---|
| 神諭 | 關係型 | 圖表、文檔 |
| MS SQL | 關係型 | 圖表、文檔 |
| PostgreSQL的 | 關係型 | 圖表*、文檔 |
| 標記邏輯 | 記錄 | 圖表、關係 |
| MongoDB的 | 記錄 | 鍵值、圖表* |
| 數據稅 | 寬柱 | 紀錄片、圖表 |
| Redis的 | 鍵值 | 紀錄片、圖表* |
| 數據庫 | - | 圖表、文檔 |
| 東方資料庫 | - | 圖表、文檔、關係 |
| Azure CosmosDB | - | 圖表、文檔、關係 |
表上的註釋
表中的星號表示需要保留的語句:
- PostgreSQL DBMS不支援圖資料模型,但該產品支援它 ,例如 AgensGraph。
- 就 MongoDB 而言,更正確的說法是談論查詢語言中圖運算子的存在(, )而不是支援圖模型,儘管當然,它們的引入需要在物理儲存層級上在支援圖模型的方向上進行一些最佳化。
- 對於 Redis,我們指的是擴展 .
接下來,對於每個類,我們將展示如何在該類別的 DBMS 中實現對多個模型的支援。我們將認為關係模型、文件模型和圖形模型是最重要的,並使用特定 DBMS 的範例來展示「缺少的模型」是如何實現的。
基於關係模型的多模型DBMS
目前領先的 DBMS 是關係型 DBMS;如果 RDBMS 沒有朝多建模方向發展,則 Gartner 的預測就不能被認為是正確的。他們展示了。現在,多型號 DBMS 就像一把瑞士刀,什麼都做不好的想法可以直接指向 Larry Ellison。
然而,作者更喜歡在 Microsoft SQL Server 中實現多建模,在此範例中將描述 RDBMS 對文件和圖形模型的支援。
MS SQL Server 中的文件模型
Habré 上已經有兩篇關於 MS SQL Server 如何實現對文件模型的支援的優秀文章;我將僅限於簡短的複述和評論:
MS SQL Server 支援文件模型的方式對於關係式 DBMS 來說非常典型:建議將 JSON 文件儲存在普通文字欄位中。對文檔模型的支援是提供特殊的運算子來解析此 JSON:
- 提取標量屬性值,
- 提取子文檔。
兩個運算子的第二個參數都是類似 JSONPath 的語法中的表達式。
抽像地說,我們可以說以這種方式儲存的文件不是關係 DBMS 中的“一流實體”,與元組不同。具體來說,在 MS SQL Server 中,目前 JSON 文件的欄位沒有索引,這使得很難使用這些欄位的值來連接表,甚至使用這些值來選擇文件。但是,可以為此類欄位建立計算列並在其上建立索引。
此外,MS SQL Server 還提供了使用運算子從表內容方便地建立 JSON 文件的能力 - 在某種意義上,與前一種傳統儲存相反的可能性。顯然,無論 RDBMS 有多快,這種方法都與文件 DBMS 的想法相矛盾,文檔 DBMS 本質上存儲的是流行查詢的現成答案,並且只能解決易於開發的問題,而不能解決速度問題。
最後,MS SQL Server 可讓您解決文件建置的逆問題:您可以使用下列命令將 JSON 分解為表格: 。如果文件不完全平整,您將需要使用 CROSS APPLY.
MS SQL Server 中的圖形模型
Microsoft SQL Server 中也完全實現了對圖 (LPG) 模型的支持 :建議使用專門的表來儲存節點和儲存圖邊。此類表是使用表達式建立的 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 中文件和圖形模型實現的描述,我要指出的是,主要從語言設計的角度來看,一個模型在另一個模型之上的這種實現似乎並不成功。有必要用一種語言擴展另一種語言,這些語言並不完全“正交”,相容性規則可能相當奇怪。
基於文件模型的多模型DBMS
在本節中,我想使用其中不是最受歡迎的 MongoDB 範例來說明文件 DBMS 中多模型的實作(如前所述,它只有條件圖運算符 $lookup и $graphLookup,不適用於分片集合),而是使用更成熟和「企業」DBMS 的範例 .
因此,讓集合包含一組以下類型的 XML 文件(MarkLogic 還允許您儲存 JSON 文件):
<Person INN="631803299804">
<name>John</name>
<surname>Smith</surname>
</Person>MarkLogic 中的關係模型
可以使用以下命令建立文件集合的關係視圖 (元素的內容 value 在下面的範例中可以是任意 XPath):
<template >
<context>/Person</context>
<rows>
<row>
<view-name>Person</view-name>
<columns>
<column>
<name>SSN</name>
<value>@SSN</value>
<type>string</type>
</column>
<column>
<name>name</name>
<value>name</value>
</column>
<column>
<name>surname</name>
<value>surname</value>
</column>
</columns>
</row>
<rows>
</template>您可以使用 SQL 查詢(例如,透過 ODBC)對建立的檢視進行定址:
SELECT name, surname FROM Person WHERE name="John"不幸的是,顯示模板建立的關係視圖是唯讀的。當處理它的請求時,MarkLogic 將嘗試使用 。在此之前,MarkLogic 的關係視圖非常有限,完全 並且可寫,但現在它們被認為已被棄用。
MarkLogic 中的圖模型
有了對圖(RDF)模型的支持,一切都差不多了。再次在幫助下 您可以根據上面的範例建立文件集合的 RDF 表示形式:
<template >
<context>/Person</context>
<vars>
<var>
<name>PREFIX</name>
<val>"http://example.org/example#"</val>
</var>
</vars>
<triples>
<triple>
<subject><value>sem:iri( $PREFIX || @SSN )</value></subject>
<predicate><value>sem:iri( $PREFIX || surname )</value></predicate>
<object><value>xs:string( surname )</value></object>
</triple>
<triple>
<subject><value>sem:iri( $PREFIX || @SSN )</value></subject>
<predicate><value>sem:iri( $PREFIX || name )</value></predicate>
<object><value>xs:string( name )</value></object>
</triple>
</triples>
</template>您可以使用 SPARQL 查詢來處理產生的 RDF 圖:
PREFIX : <http://example.org/example#>
SELECT ?name ?surname {
:631803299804 :name ?name ; :surname ?surname .
}與關係模型不同,MarkLogic 透過另外兩種方式支援圖模型:
- DBMS 可以是 RDF 資料的成熟的獨立儲存(其中的三元組將被稱為 與上面描述的相反 ).
- 特殊序列化中的 RDF 可以簡單地插入 XML 或 JSON 文件中(然後三元組將被稱為 )。這可能是機制的替代方案
idref等等
關於 MarkLogic 中事物「真正」如何運作的一個好主意是 ,從這個意義上說,它是低階的,儘管它的目的恰恰相反——嘗試從所使用的資料模型中進行抽象,以確保不同模型中的資料、事務性等的一致工作。
「沒有主模型」的多模型 DBMS
市場上也有一些DBMS最初將自己定位為多模型,沒有任何繼承的主模型。這些包括 , (自 2018 年起,開發公司屬於 SAP)和 (作為 Microsoft Azure 雲端平台一部分的服務)。
事實上,ArangoDB 和 OrientDB 都有「核心」模型。在這兩種情況下,這些都是它們自己的資料模型,是文件模型的概括。這些概括主要是為了促進執行圖和關係性質的查詢的能力。
這些模型是唯一可在指定的 DBMS 中使用的模型;它們自己的查詢語言旨在與它們一起使用。當然,這樣的模型和 DBMS 是有前途的,但缺乏與標準模型和語言的兼容性使得無法在遺留系統中使用這些 DBMS——替換那裡已經使用的 DBMS。
Habré 上已經有一篇關於 ArangoDB 和 OrientDB 的精彩文章: .
數據庫
ArangoDB 聲稱支援圖形資料模型。
ArangoDB 中圖的節點是普通文檔,邊是特殊類型的文檔,與常規系統字段一起,具有 (_key, _id, _rev) 系統字段 _from и _to。文檔 DBMS 中的文檔傳統上被組合成集合。表示邊的文檔集合在 ArangoDB 中稱為邊集合。順便說一句,邊集合文檔也是文檔,因此 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 : "Джон Донн" }
]更多查詢和結果
如果上面的結果格式似乎對於關係 DBMS 比對於文件 DBMS 更典型,您可以嘗試此查詢(或者您可以使用 ):
FOR p IN persons
RETURN {
person : p.name,
likes : (
FOR c IN OUTBOUND p likes
RETURN c.name
)
}結果將如下所示:
[
{ "person" : "Алиса" , likes : ["Жан-Жак" , "Джон Донн"] } ,
{ "person" : "Боб" , likes : ["Джон Донн"] }
]東方資料庫
在 OrientDB 中在文件模型之上實現圖模型的基礎是 文件字段,除了或多或少的標準標量值外,還有以下類型的值 LINK, LINKLIST, LINKSET, LINKMAP и LINKBAG。這些類型的值是連結或連結的集合 文件。
系統指派的文檔標識符具有“物理意義”,表示記錄在資料庫中的位置,如下所示: @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 必須自行監控引用完整性,而圖形 API 則承擔這項工作。但讓我們看看在未整合到程式語言中的「純」查詢語言中對 OrientDB 的存取是什麼樣的。
查詢和結果
與 OrientDB 中 ArangoDB 範例中的查詢類似的查詢如下所示:
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 的查詢語言可以描述為具有類似 Gremlin 插入的 SQL。在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中的多模型只是使用一個製造商支援不同模型的多個資料庫的能力,這並不能解決多變量儲存的所有問題。
基於圖模型的多模型 DBMS?
值得注意的是,市場上還沒有基於圖模型的多模型 DBMS(除非我們考慮同時支援兩個圖模型:RDF 和 LPG;請參閱 )。最大的困難是在圖模型之上實現文件模型而不是關係模型造成的。
在圖模型形成的過程中就考慮如何在圖模型之上實現關係模型的問題。如何 例如, :
圖方法中沒有任何固有的東西可以阻止在圖資料庫上建立一個層(例如,透過適當的索引),該層支援關係視圖,(1)從通常的鍵值對中恢復元組,(2)對按關係類型劃分的元組。
在圖模型之上實作文件模型時,您需要記住以下幾點:
- JSON 陣列的元素被認為是有序的,但從圖的邊的頂點發出的元素則不是;
- 文檔模型中的資料通常是非規範化的;您仍然不想儲存同一嵌入文檔的多個副本,並且子文檔通常沒有標識符;
- 另一方面,文檔 DBMS 的想法是文檔是現成的“聚合體”,不需要每次都重新建構。要求圖模型能夠快速取得成品文件對應的子圖。
有點廣告
這篇文章的作者與NitrosBase DBMS的開發相關,其內部模型是圖,外部模型——關係模型和文件模型——是其表示。所有模型都是平等的:幾乎任何資料都可以使用其自然的查詢語言在其中任何一個中獲得。而且,在任何視圖中,資料都可以變更。變更將反映在內部模型中,並相應地反映在其他視圖中。
我希望在下面的一篇文章中描述 NitrosBase 中的模型匹配是什麼樣子的。
結論
我希望讀者已經或多或少地了解了所謂的多建模的整體輪廓。多模型 DBMS 有很大不同,「多模型支援」可能看起來也不同。要了解每種特定情況下什麼是“多模型”,回答以下問題很有用:
- 我們是在談論支持傳統模型還是某種「混合」模型?
- 這些模型是否“平等”,或者其中一個模型是其他模型的主題?
- 模型之間是否「無關緊要」?在一種模型中寫入的資料可以在另一種模型中讀取甚至覆蓋嗎?
我認為關於多模型 DBMS 的相關性的問題已經可以得到肯定的回答,但有趣的問題是在不久的將來,哪種類型的需求會更大。看來支援傳統模型(主要是關係模型)的多模型 DBMS 的需求將會更大;多模型 DBMS 的普及提供了結合各種傳統模型優點的新模型,這是一個更遙遠的未來問題。
只有註冊用戶才能參與調查。 , 請。
您使用多模型 DBMS 嗎?
我們不使用它,我們將所有內容儲存在一個 DBMS 和一個模型中
我們使用傳統 DBMS 的多模型功能
我們實踐多語言持久性
我們使用新的多模型 DBMS(Arango、Orient、CosmosDB)
19 位用戶投票。 4 名用戶棄權。
來源: www.habr.com
