漫談數據庫模型

數據庫是軟件世界裏的基礎。它是現實世界的投射,反應了開發者對現實世界的思考以及對其的抽象;一旦決定了數據庫選型,數據庫便會對軟件/應用造成深遠影響,它決定了開發者對數據的處理方式。

數據庫自二十世紀中期以來,誕生了像網狀數據庫(Network Database)、層次數據庫(Hierarchical Database)、關係型數據庫(Relational Database)等很多種有趣的數據庫模型,有些數據庫模型發揮了其作用後,逐漸消失在歷史的塵埃中;有些數據庫模型經受住了歷史地考驗,如今依然站立在時代的潮頭。數據庫的發展並不因爲其歷史悠久而停滯,而是隨着新的業務場景和新的挑戰不斷出現,促使着新的數據庫模型也在不斷地提出,更好地適應新的業務場景和解決新的挑戰。

本文僅當作拋磚引玉,供大家參考。

歷史的遺留

在軟件發展的歷史上,有很多盛極一時的數據庫模型,或多或少有着一些致命性的缺點,慢慢地只存在於遺留系統中,或者是解決一些特定的問題。如果讀者不感興趣的話,可以直接跳到關係型數據庫的那個章節。

文件型數據庫(Flat-file Database)

文件型數據庫可以認爲是最簡單的一種數據庫模型,其實現非常簡單,就是讀寫一個簡單的文件,分隔符多樣,文件類型可以是CSV、TSV或者是JSON文件。數據直接以人類可讀的形式呈現,程序也比較容易解析。

下面的代碼來源於《Designing Data-Intensive Application》一書,可以實現簡單的文件型數據庫讀取和寫入。

#!/bin/bash 

db_set () {                
    echo "$1,$2" >> database 
}

db_get () {
   grep "^$1," database | sed -e "s/^$1,//" | tail -n 1 
}

文件型數據庫其實現非常簡單,同樣地這也限制了它的使用。例如在併發和並行的場景下,文件型數據庫就表現的不是那麼友好,且讀取性能不是那麼優秀,單點查詢和範圍查找的需要從頭遍歷整個文件。

儘管其有種種種不足,因爲其簡單的實現,現代操作系統依然會使用其作爲內部配置文件(/etc/passwd/etc/fstab),特別是 Linux 系統。

數據庫實現:

  • Linux 系統裏的/etc/passwd/etc/fstab文件

層次數據庫(Hierarchical Database)

層次數據庫模型誕生於1960年代,是文件型數據的下一個形態。層次數據庫模型類似於一個樹狀結構,每條記錄有且僅有一個父節點,類似於下圖。

層次數據庫是人們第一次嘗試去思考和處理複雜數據,在一定程度上提升了文件型數據庫的一些特定數據讀取方式的性能,但是層次數據庫是基於樹狀的模型,訪問層次數據庫類似於遍歷鏈表,很難實現對複雜數據的讀取。

 

v2-c0688ab155fb4eb2cd723865174448a9_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

雖然層次數據庫在現代系統中沒有什麼太大的應用價值,但是它依然使用在Linxu/Windows文件系統、DNS和LDAP系統中。

數據庫實現:

  • Linxu/Windows文件系統
  • DNS
  • LDAP

網狀數據庫(Network Database)

網狀數據庫也誕生於1960年代。數據系統語言會議(CODASYL)的委員會標準化了網狀數據庫模型,因此網狀數據庫模型也被稱爲 CODASYL 模型。

 

v2-e3522e6221e35c4cd1efc42807889d8a_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

網狀數據庫進一步發展了層次數據庫模型,解決了層次數據庫有且僅有一個父節點的問題。網狀數據庫模型的子節點可以擁有多個父節點,同時這也帶來了更高的複雜性。

和層次數據庫模型一樣,網狀數據庫模型的查詢和更新都需要遍歷鏈表,給開發帶了無盡的難度,這使得網狀數據庫模型逐漸沒落。畢竟能使用網狀數據庫模型的地方,都能找到更好的替代品。

數據庫實現

  • IDMS

關係型數據庫(Relational databases)

關係型數據庫模型誕生於1960年代,是現存的數據庫模型中活得最久、生命力最旺盛、使用的最爲廣泛的數據模型。關係型數據庫模型在剛提出來時,並不受到待見,但是在二十世紀八十年代成爲了絕大多數人的首選數據庫。

 

v2-2b2c3ed4b6b3454657abc5a676b0eeea_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

 

關係型數據庫模型基於關係代數,它認爲:數據可以被組織成關係(SQL中稱作表),其中每個關係是元組(SQL中稱作行)的無序集合。換句話說,一個關係(表)只是一個元 組(行)的集合。

關係型數據庫模型解決了層次數據庫模型無法表達多對多關係的能力;在關係型數據庫中,讀取數據時不再需要像訪問鏈表一樣去訪問數據,開發者可以隨意讀取表中的任意行和列;並且關係型數據庫引入了外鍵的概念,使得表和表之間可以輕易的關聯起來。

適用於關係型數據庫的查詢語言是SQL。SQL作爲一個圖靈完備的語言,已經不僅僅侷限於關係型數據庫,而是成爲數據庫領域中當之無愧的王者。SQL的核心在於查詢優化器,由查詢優化器自動決定SQL的哪些部分以哪個順序執行,以及使用什麼索引。

總的來說,關係型數據庫模型以其強大的靈活性和適應力成爲了開發者的首選數據庫模型。

數據庫實現:

  • MySQL
  • PostgreSQL
  • SQLite

NoSQL數據庫

NoSQL誕生於二十一世紀,剛開始是爲了推翻關係型數據庫的統治地位,提供更強大的分佈式能力,即“No SQL”,到後來逐漸發展爲“Not Only SQL”,自身作爲了關係型數據庫的補充。

NoSQL數據庫相比於關係型數據擁有以下的優勢:

  • 更好的可擴展性;
  • 更推崇免費與開源。

鍵值數據庫(Key-Value Database)

鍵值數據庫誕生於二十世紀七十年代,但是到了二十一世紀初纔開始廣泛應用。鍵值數據庫模型非常簡單,數據存儲包括鍵(Key)和值(Value),開發者通過指定的鍵可以查到特定的數據值。

 

v2-b318c0e0b6a36e79ab0b90b71cf143d3_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

 

值的格式可以多種多樣,例如圖片、文件或者是字符串。一般來說,鍵值數據庫並不會要求數據有着嚴格的格式要求,其客戶端也僅僅提供了有限的幾種方式進行交互。

鍵值數據庫使用起來非常簡單,因此在着特定需求的業務有着非常好的作用,例如存儲配置文件、緩存數據、狀態信息。

但由於鍵值數據庫並不對數據的類型和格式進行檢查,因此需要開發者自己保證數據合規和數據類型正確。

數據庫實現:

  • Redis
  • memcached
  • etcd

文檔數據庫(Document databases)

文檔數據庫模型是在2009年後興起的數據庫模型。文檔數據庫模型與鍵值數據庫模型類似,也有着唯一的ID作爲鍵,但是與鍵值數據庫模型不同的是,文檔數據庫模型Value是結構化的數據,例如JSON、BSON或者是XML格式。

 

v2-ea6ce770d3de33cbabcf24379205b1cb_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

 

儘管文檔數據庫模型的Value是結構化的數據,但是數據本身是沒有嚴格需要提前定義的Schema的。因此文檔數據庫裏的每一個文檔都有可能有着不同的格式,是可以被進一步查詢和解析的。

文檔數據庫彌補了關係型數據庫和麪向對象的編程語言的阻抗不匹配(impedance mismatch),擁有極大的架構靈活性。

因爲文檔數據庫不需要提前定義Schema,可以減少應用程序對Join的需求,但是應用程序需要做額外的工作來保持數據的一致性:通過向數據庫發出多個請求,在應用程序代碼中模擬Join。但是這也將複雜性轉移到應用程序中,這要比由數據庫內的專用代碼執行的Join更慢。

總的來說,文檔數據庫對於創業公司是一個很好的選擇,因爲開發者可以很輕易的改變數據存儲的結構,而不影響現有的數據。但是要注意,文檔數據庫模型的靈活性對於保持數據一致性會是一個極大的挑戰。

數據庫實現:

  • MongoDB
  • RethinkDB
  • Couchbase

圖數據庫(Graph databases)

圖數據庫興起於2000年代。圖數據庫使用node、edge和properties的概念去描述數據。

 

v2-35cda62068c9f2253029eb737e045616_720w.jpguploading.4e448015.gif轉存失敗重新上傳取消

 

 

圖數據庫將數據表達爲一個單獨的node,node擁有着任意數量的properties。在每個node之間,使用edge(也被稱爲relationship)關聯。從某種意義上來說,圖數據庫將相關數據放入到node中,並且通過edge關聯起這些數據。因此常用於表達數據之間的聯繫。

圖數據庫最常見的用途就是查詢在社交網絡中兩個用戶之間的聯繫。關係型數據庫需要join多張表,而圖數據庫能直接查詢出來。

數據庫實現:

  • Neo4j
  • JanusGraph
  • Dgraph

列簇數據庫(Column-family databases)

列簇數據庫興起於2000年代,通常也被稱爲非關係型列式存儲(non-relational column stores)、寬列(wide-Column)數據庫,屬於NoSQL的一種,但是從客戶端看起來很像關係型數據庫。

 

 

 

與關係型數據庫一樣,列簇數據庫也有行和列的概念,但是這兩個概念的本質是完全不同的。

在關係型數據庫裏,一個schema定義了一張表裏的列,具體了某個列應該在哪個地方,還有相對應的數據類型等等。所有行都使用一個固定的schema。除了Table的概念以外,列簇數據庫有着固定的結構,稱爲列簇。列簇包括了一定行的數據,每一行定義它們自己的格式。每一行數據有着唯一的列標識符,用來確定某一列的數據。

基於這個設計,列簇裏的每一行都有着自己獨有的schema。這個schema非常靈活,它的改變只會影響到單獨的行。因此你可以把列簇數據庫理解爲另一種形式的鍵值數據庫。

列簇數據庫擁有優異的可擴展性,因爲所有列都放在一塊,因此無需大量的join操作。

但是列簇數據庫不是萬能的,如果你的數據需要大量的join,列簇數據庫就不是一個很好的選擇,同樣的,類似於求和、求平均以及其它類型的分析型操作都不適合列簇數據庫。

數據庫實現:

  • Cassandra
  • Hbase

NewSQL

NewSQL誕生於2010年代。NoSQL數據庫對於很多場景來說都是一個非常棒的數據庫模型,特別是那種傳統關係型數據不能勝任的場景。因爲NoSQL誕生於當代,因此它們更關注於高性能和可用性。

從關係型數據庫誕生以來都沒有一種方案給它們帶來可擴展性。爲了解決這種需求,新型的關係型數據庫誕生了,它們被稱爲NewSQL。

NewSQL數據庫有着關係型數據庫的結構和特徵,但是它們更加現代,擴展性更好。它們的目標就是提供比關係型數據庫更好的可擴展性,比NoSQL更好的一致性保證。爲了達到這個目的,NewSQL在網絡必然出現波動的情況下犧牲了一定的可用性。

爲了解決可用性的問題,新的架構被發展出來以減少網絡分區的影響。例如對數據進行數據切分,減少網絡分區對全局數據造成影響。更深入地說,NewSQL提供了某種機制去自動切換集羣地成員角色。

NewSQL提供了與傳統關係型數據類似的特徵,因此需要區分它們和傳統關係型數據庫的差異。NewSQL數據庫沒有傳統關係型數據庫那樣完備的數據庫特徵,通常也僅僅只會提供完整SQL標準的子集。許多NewSQL數據庫需要大量的內存緩存數據,提高性能的同時也承擔了丟失數據的分享。

NewSQL數據庫很適合那種需要關係型數據庫的且有需要可擴展性的場景,未來它們會是比NoSQL更好的替代品。

數據庫實現:

  • MemSQL
  • VoltDB
  • Spanner
  • Calvin
  • CockroachDB
  • FaunaDB
  • yugabyteDB

總結

本文簡單的介紹了遠古時代的數據庫模型層次數據庫、網狀數據庫,現在的主流數據庫模型關係型數據庫、NoSQL數據庫以及正在風頭上的的NewSQL數據庫,它們的誕生不是無緣無故的,都是應某種需求而生。每一種數據庫模型都有着鮮明的特點,及其擅長的領域。

但是在計算機世界裏,沒有一種萬能的銀彈能解決所有問題。開發者需要根據自己遇到的問題和情況選擇合適的數據庫模型:使用存儲配置信息時,關係型數據庫模型就不適合了,而是要選擇鍵值數據庫模型;遇到多對多的關係時,關係型數據庫模型比文檔數據庫模型更合適。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章