(DDIA)SQL與NoSQL數據模型簡介

翻譯《Designing Data-Intensive Applications》
作者:Martin Kleppmann
譯者:雨釣(有增改)

一、SQL與NOSQL起源與優劣對比

1.1、SQL

今天最著名的數據結構可能就是SQL了,一種基於Edgar Codd在1970年提出的關係模型: 數據被組織成關係(SQL中的表),其中每個關係是一個無序的元組集合(SQL中的行), 關係模型是一個理論上的建議,許多人當時懷疑它是否能有效地實現。 然而,到20世紀80年代中期,關係數據庫管理系統(RDBMSes)和SQL已經成爲大多數人的首選工具,他們需要存儲和查詢帶有某種regular結構的數據。 關係數據庫的主導地位持續了大約25-30年——這在計算曆史上是絕無僅有的;

關係數據庫的根源在於業務數據處理,主要是執行在上世紀六、七十年代的一種大型計算機上。它所針對的用例從今天的角度來看是很平常的,例如:典型的交易處理(銷售或銀行中轉業務,航空公司預訂,倉庫庫存)和批處理( 用戶的發票、工資、報告)。哪些當時與關係型數據庫共存的其他數據庫,由於其本身設計的問題,使得應用程序開發人員需要對數據庫中數據的內部結構進行大量的思考和優化。而與之相反,關係模型的目標是將實現細節隱藏在一個更乾淨的接口後面。

多年來,針對於數據存儲和查詢的方法有很多。 20世紀70年代和80年代初,網絡模型和層次模型是當時主要的選擇。 但是伴隨着關係模式的出現和快速發展,關係模型主鍵佔據主導地位。 在上世紀80年代末和90年代初,Object數據庫再次出現, XML數據庫出現於本世紀初,但只出現了小衆的採用。 關係模型的每個競爭對手在這段時間內都進行了大量的宣傳和炒作但是仍然未能生存下來。

隨着計算機變得更加強大和網絡化,它們開始被用於越來越多樣化的場景。值得注意的是,關係數據庫在其原始的業務數據處理範圍之外,非常好地推廣到針對WEB的應用上。 你在web上看到的許多東西仍然是由關係數據庫驅動的,比如在線發佈、討論、社交網絡、電子商務、遊戲、軟件服務等等。

1.2、The Birth of No SQL

2010年 出現的NOSQL是推翻關係模型統治地位的一次最新嘗試。“No SQL”這個名字是不準確的,因爲它實際上並不是指任何特定的技術——它最初只是一個簡單的Twitter在2009年提出的一個標籤,主要關於分佈式,非關係數據庫,只後很快就傳遍了業界。現在,許多有趣的數據庫系統都與No SQL相關,並且它被重新定義爲***NOT Only SQL***。

在NO SQL數據庫的情況下,有幾個驅動因素,包括:

  • 比關係型數據庫更好的擴展性,包括更大的數據集以及吞吐量。

  • 更好的開源特性而不是商業化的。

  • 擁有關係模型所不支持的特定查詢操作

  • 拋棄了關係模型中對schema的限制,支持更動態和更具代表性的數據模型

不同的應用程序有不同的需求,對於一個用例場景來說,最好的技術選擇可能與另一個用例的最佳選擇是不同。因此,在可預見的將來,關係數據庫將繼續與廣泛的非關係數據存儲共存,這一概念有時被稱爲***polyglot persistence***

二、The Object-Relational Mismatch

當今大多數應用程序開發都是在面向對象的編程語言中完成的,這導致了開發人員對SQL數據模型存在很多意見,因爲如果數據存儲在關係表中,那麼在應用代碼中的對象(面向對象的語言,如JAVA)和關係型模型中的表之間需要一個笨拙的轉換層。 模型之間的討論有時被稱爲***impedance mismatch***( 從電子產品中借用的術語。每個電路的輸入和輸出都有一定的阻抗。當你將一個電路的輸出連接到另一個電路的輸入時,如果兩個電路的輸出和輸入阻抗匹配,連接上的power transfer就會最大化。阻抗不匹配會導致信號反射和其他問題)

因此則常見的面向對象的開發中,如JAVA Web項目中通常會使用如Active Record和Hibernate等***對象-關係映射(ORM)框架***,以減少這個翻譯層所需的樣板代碼量。但它們並不能完全隱藏這兩個模型之間的差異。

圖2-1

例如,上圖說明了在關係模式中如何表示一份簡歷(概要文件中的鏈接)。整個文件可以通過一個唯一一的標識符user_id來標識, 像first_name和last_name這樣的字段恰好顯示爲每一個用戶,因此它們可以被建模爲users表上的列。 然而,大多數人在他們的職業(職位)中有不止一份工作,而且人們可能會有很多的教育時期和任何數量的聯繫信息,從用戶和項目之間具有一對多的關係,可以用不同的方式表示:

  • 1、在傳統的SQL模型(在SQL:1999之前)中,最常見的標準化 的 表現是將位置、教育和聯繫信息放在不同的表中,並通過外鍵引用放在users表中,如圖所示。

  • 2、後來版本的SQL標準增加了對結構化數據類型和xml數據的支持;允許將多值數據存儲在單個行中,並支持在這些文檔中查詢和索引。這些特性在Oracle、IBM DB2、MS SQL Server和Post‐gre SQL(6、7)進行了不同程度的實現。JSON數據類型也被幾個數據庫所支持,包括IBM DB2、SQL和Postgre SQL。

  • 3、第三種選擇是將工作、教育和聯繫信息作爲JSON或XML Document進行編碼,將其存儲在數據庫的文本列上,並讓應用程序對其結構和內容進行優先處理。在這個設置中,通常無法使用數據庫查詢在編碼列內的值。

對於像上面提到的類似簡歷這樣的數據結構,它通常是一個自包含的文檔,JSON可能非常合適:參見示例2-1。JSON相較於XML而言要簡單得多,因此也更具吸引力。面向文檔的數據庫如Mongo DB、Rethink DB、Couch DB和Espresso都支持這個數據模型。

Example 2-1. Representing a Linked In profile as a JSON document

{  
   "user_id":     251,
   "first_name":  "Bill",
   "last_name":   "Gates",
   "summary":     "Co-chair of the Bill & Melinda Gates... Active blogger.",
   "region_id":   "us:91",
   "industry_id": 131,
   "photo_url":   "/p/7/000/253/05b/308dd6e.jpg",
   "positions": [   
      {"job_title": "Co-chair","organization": "Bill & Melinda Gates Foundation"},
      {"job_title": "Co-founder, Chairman", "organization": "Microsoft"}
   ],
  "education": [   
      {"school_name": "Harvard University",       "start": 1973, "end": 1975},
      {"school_name": "Lakeside School, Seattle", "start": null, "end": null} 
   ],  
  "contact_info": {   
  "blog":    "http://thegatesnotes.com",    
  "twitter": "http://twitter.com/BillGates" 
   }
}

三、JSON

一些開發人員認爲,JSON模型減少了應用程序代碼和存儲層之間的阻抗不匹配(impedance mismatch)。但是,接下來我們將看到,JSON作爲一種數據編碼格式也存在一些問題。同時缺乏schema常常被認爲是一種優勢。

JSON表示比圖2-1中多表模式具有更好的局部性。 如果您想在關係數據庫示例中獲取一個簡歷文件,您需要執行多個查詢(通過user_id查詢每個表),或者在users表及其附屬表之間執行一個混亂的多路JOIN。在JSON表中,所有相關信息都在一個地方,一個查詢就足夠了。

用戶位置、教育歷史和聯繫信息的一對多關係可以表示成數據中的樹結構,而json表示的樹結構顯式如圖2-2所示:

圖2-2

四、Many-to-One and Many-to-Many Relationships

在前一節中,以圖2-1爲例,區域id和行業id被指定爲ID,而不是純文本字符串“Greater Seattle Area”和“Philanthropy”。思考下這是爲什麼?

如果用戶界面有需要輸入的諸如“區域”或“行業”等文本字段,那麼沒有將它們(行業和區域)存儲爲純文本字符串是有意義的。 同時,將地理位置信息抽取出來組成一張表也是有好處的:

  • 1、有助於保持一致的風格和拼寫
  • 2、避免歧義 (e.g., if there are several cities with the same name)
  • 3、易於更新-the name is stored in only one place, so it is easy to update across the board if it ever needs to be changed (e.g., change of a city name due topolitical events)
  • 4、本地化支持—when the site is translated into other languages, the stand‐ardized lists can be localized, so the region and industry can be displayed in theviewer’s language
  • 5、方便更好的查詢—e.g., a search for philanthropists in the state of Washington can match this profile, because the list of regions can encode the fact that Seattle is in Washington (which is not apparent from the string “Greater Seattle Area”)

是否存儲ID或文本字符串主要考慮的是重複問題。 當您使用ID時,對人類有意義的信息(例如“Philanthropy慈善”)只存儲在一個地方,所有引用的信息都使用一個ID(在數據庫中只有這個ID)。 當你直接存儲文本時,你將在每個使用它的記錄中複製具有人類意義的文本信息,存儲的佔用會更高。 使用ID的優點是,因爲它對人類沒有意義,所以即使它標識的信息發生了變化,它也不需要改變。而任何對人類有意義的事情都可能在未來的某個時候發生變化——如果這些信息被複制,所有多餘的副本都需要更新。 這就會導致寫過多的開銷,並且會出現不一致的風險(有些信息會被更新,而有些則沒有更新)。消除這種重複是數據庫標準化的關鍵思想。

不幸的是對數據進行規範化需要多對一的關係(many-to-one )例如,許多人生活在同一個區域,許多人在同一個行業工作等,此時人與區域,人與行業都是多對一關係,這種多對一關係並不適合文檔數據模型(document model)。而在關係型數據庫中通常通過ID引用其他表中的行,因此在關係型數據庫中JOIN很容易。但是在document model中join操作對於一對多(one-to-many)的樹形結構並不是必須的,並且對Join的支持非常差。

如果數據庫本身不支持JOIN,那麼就需要在應用端代碼中通過多次查詢數據庫模擬JOIN操作(在上面提到的這種情況下,區域和行業列表可能很小,你可以把他們保存在內存中,但是這樣做相當於把JOIN的工作從數據庫中轉移到應用端代碼中了)

此外,即使應用程序的初始版本很適合無連接的document model,但是隨着應用程序功能的不斷添加,數據會傾向於變得更加具有關聯性。

五、Relational Versus Document Databases Today

當比較關係型數據與Document數據庫時有很多需要考慮的地方,包括他們的容錯性,併發處理能力。這裏我們僅僅對數據模型進行對比。

Document模型的最大優勢是***schema靈活***,同時對於一些應用而言,他與一些應用代碼中所使用的數據結構很相似。而關係型數據庫的優勢是提供JOIN和更好的對多對一關係支持,以及多對多的支持。

六、Which data model leads to simpler application code?

如果你的應用的數據結構類似文檔(例如一個一對多的樹型結構,且通常一次加載整個樹)那麼Document將非常合適;而關係技術將一個類似文檔的結構撕裂成幾個碎片化的表,會導致複雜的schema和複雜的應用程序代碼。

文檔數據庫也有限制,例如你不能直接引用文檔中未定義的項目,例如你通常需要這樣描述:“用戶251的職位列表中第二個職位”(很像層級模型中的訪問路徑),然而只要文檔沒有太深的嵌套,這通常不是問題。

而文檔數據庫對JOIN的支持不足,可能是問題,也可能不是問題,這主要取決於應用。例如利用文檔數據庫記錄某個時間點發生的事件並分析的應用中,可能不需要多對多關係。然而如果你的應用中確實需要多對多關係,那麼Document數據庫就不那麼吸引人了。它可能導致需要使用非常規的手段來實現JOIN操作,此外應用程序也需要添加額外的代碼來保證數據一致性:通過向數據庫發送多個請求可以在應用端實現JOIN操作,但是這樣會將複雜性轉移到應用程序中,同時,這樣做通常比在數據庫中執行的JOIN要慢。因此在這種情況下,會導致應用程序更加複雜以及更糟糕的性能。

一般來說,無法肯定哪個數據庫一定會導致應用程序更加複雜,它主要取決於數據之間的關係類型,對於高度互聯的數據,文檔數據庫是笨拙的,而關係型數據庫是有效的,圖數據庫是更加自然的

七、Schema flexibility in the document model

大多數的document數據庫以及支持JSON的關係型數據庫不會對document中的數據進行任何強制的schema,在關係型數據庫中支持XML時通常帶有可選的schema驗證。當沒有schema時,任意的key和value都可以插入到document中,同時在讀取數據時客戶端對數據也沒有任何保證。

document數據庫通常也被稱爲***schemaless***,這樣稱呼有一些誤導的意思,因爲在代碼讀取數據時通常採用某種結構來解析數據,例如是一個隱式的schema,只是沒有被數據庫強制執行。一個更準確的詞應該是:schema-on-read(數據的結構是隱式的,只有當讀取數據時才使用該結構去解析)***。與之相應的 是***schema-on-write(通常在關係型數據庫中被採用,schema是顯示的,數據庫會確保所有的數據都符合schema)

***Schema-on-read***類似於編程語言中的動態類型檢查,相反,***Schema-on-write***就是靜態類型檢查。正如開發人員對於靜態類型檢查和動態類型檢查有很大爭論一樣 ,數據庫中schema的實現也是一個有很大爭議的額話題,無關沒有對錯。

當應用程序想要更改他的數據格式時,這兩種模式的差異將會非常明顯;假如,當前你正在將每個用戶的全名存儲在一個字段中,然而不久之後你希望姓和名分開存儲。在document數據庫中,你需要使用一個新的document用來寫first name,同時在應用程序中當讀取老的數據時需要進行如下處理:

if (user && user.name && !user.first_name) {
    // Documents written before Dec 8, 2013 don't have first_name
    user.first_name = user.name.split(" ")[0];
}

而另一方面,在靜態類型schema的數據庫中,你需要進行遷移:

ALTER TABLE users ADD COLUMN first_name text;
UPDATE users SET first_name = split_part(name, ' ', 1);      -- Postgre SQL
UPDATE users SET first_name = substring_index(name, ' ', 1);      -- My SQL

schema修改的代價是需要停機時間,這個代價是非常昂貴且完全不值得的。大多數的關係型數據在執行 ALTER TABLE語句的耗時約在幾秒內,Mysql是一個明顯的例外, 它可以在ALTER table上覆制整個表,這意味着在修改一個大型表時,可能需要幾分鐘甚至幾個小時的停機時間——儘管有各種各樣的工具在這個限制下工作。

在大表上運行UPDATE語句可能會在任何數據庫上都很慢,因爲每一行都需要重寫。通常這是不可接受的,當然你也可以在應用程序中進行處理,將first_name設置爲NULL,並在讀取時填充它,就像使用文檔數據庫一樣。但是在schema-on-read模式下是危險的,如果一個集合中的所有元素因爲一些原因(例如數據是多樣的)導致結構並不是一致,例如:有許多不同類型的對象,將每種類型的對象放到各自的表中是不切實際的,數據的結構是由外部系統決定的,而這些系統是您所控制的,並且隨時可能發生變化。

在這種情況下,一個schema可能會過大於功,而schemaless的記錄則是一個更自然的數據模型。 但是,如果所有的記錄都被期望具有相同的結構,那麼schema是用來記錄和執行結構的有用機制。我們將在之後詳細討論模式和模式演化。

相關參考文檔References

[1] Edgar F. Codd: “A Relational Model of Data for Large Shared Data Banks,” Com‐munications of the ACM, volume 13, number 6, pages 377–387, June 1970. doi:10.1145/362384.362685
[2] Michael Stonebraker and Joseph M. Hellerstein: “What Goes Around ComesAround,” in Readings in Database Systems, 4th edition, MIT Press, pages 2–41, 2005.ISBN: 978-0-262-69314-1
[3] Pramod J. Sadalage and Martin Fowler: No SQL Distilled. Addison-Wesley, August2012. ISBN: 978-0-321-82662-6
[4] Eric Evans: “No SQL: What’s in a Name?,” blog.sym-link.com, October 30, 2009.
[5] James Phillips: “Surprises in Our No SQL Adoption Survey,” blog.couchbase.com,February 8, 2012.
[6] Michael Wagner: SQL/XML:2006 – Evaluierung der Standardkonformität ausge‐wählter Datenbanksysteme. Diplomica Verlag, Hamburg, 2010. ISBN:978-3-836-64609-3
[7] “XML Data in SQL Server,” SQL Server 2012 documentation, technet.micro‐soft.com, 2013.
[8] “Postgre SQL 9.3.1 Documentation,” The Postgre SQL Global DevelopmentGroup, 2013.
[9] “The Mongo DB 2.4 Manual,” Mongo DB, Inc., 2013.
[10] “Rethink DB 1.11 Documentation,” rethinkdb.com, 2013.
[11] “Apache Couch DB 1.6 Documentation,” docs.couchdb.org, 2014.
[12] Lin Qiao, Kapil Surlaker, Shirshanka Das, et al.: “On Brewing Fresh Espresso:Linked In’s Distributed Data Serving Platform,” at ACM International Conference onManagement of Data (SIGMOD), June 2013.
[13] Rick Long, Mark Harrington, Robert Hain, and Geoff Nicholls: IMS Primer.IBM Redbook SG24-5352-00, IBM International Technical Support Organization,January 2000.
[14] Stephen D. Bartlett: “IBM’s IMS—Myths, Realities, and Opportunities,” TheClipper Group Navigator, TCG2013015LI, July 2013.
[15] Sarah Mei: “Why You Should Never Use Mongo DB,” sarahmei.com, November11, 2013.

譯者注:

17年初讀此書,驚爲神作,年末心(Kai)血(shi)來(zuo)潮(si)利用空閒時間翻譯此書,自(chun)娛(shu)自(zhuang)樂(bi)!歷時8個月完成十之七八後,終告失敗。之後會整理歸納後,希望作爲一個系列,在此記錄,聊以自慰。。。
需要提的是,18年9月份國內有三位大神已經成功出版了該書的中文版,有興趣可以去讀下。

未完待續。。。。。。。。。。。。
文章來源《Designing Data-Intensive Applications》翻譯有刪改

微信公衆號

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