Andrew C. Oliver 沈建苗
起初有文件,后來有基于結構化文件的導航數(shù)據(jù)庫,然后出現(xiàn)了IMS和CODASYL。大概40年前,出現(xiàn)了首批關系數(shù)據(jù)庫。在20世紀八、九十年代的大部分時間,“數(shù)據(jù)庫”嚴格意義上指“關系數(shù)據(jù)庫”。SQL(標準查詢語言)占主導地位。
后來隨著面向對象編程語言日益流行,一些人認為,解決面向對象語言和關系數(shù)據(jù)庫“阻抗不匹配”的辦法是在數(shù)據(jù)庫中映射對象。因此,我們最后迎來了“面向對象的數(shù)據(jù)庫”。對象數(shù)據(jù)庫方面有意思的地方是,在許多情況下,它們基本上是內(nèi)置對象映射器的普通數(shù)據(jù)庫。這種數(shù)據(jù)庫后來漸漸失寵,下一個真正的主流嘗試是2010年代的“NoSQL”。
NoSQL以同樣的方式攻擊關系數(shù)據(jù)庫和SQL。這回的主要問題是,互聯(lián)網(wǎng)顛覆了具有40年歷史關系數(shù)據(jù)庫管理系統(tǒng)(RDBMS)架構的基本前提。這種數(shù)據(jù)庫旨在節(jié)省寶貴的磁盤空間,并可縱向擴展。然而現(xiàn)在有太多的用戶和太多的任務,一臺胖服務器處理不了。NoSQL數(shù)據(jù)庫則宣稱,如果數(shù)據(jù)庫沒有連接(join),沒有標準查詢語言(因為實現(xiàn)SQL需要花費時間),也沒有數(shù)據(jù)完整性,那么就可以橫向擴展以處理眾多用戶。這解決了縱向擴展的問題,但也帶來了新問題。
與這些聯(lián)機交易處理系統(tǒng)(OLTP)并行開發(fā)的是另一種關系數(shù)據(jù)庫,名為聯(lián)機分析處理系統(tǒng)(OLAP)。這種數(shù)據(jù)庫支持關系結構,但在執(zhí)行查詢時就知道它們將返回大量數(shù)據(jù)。上世紀八、九十年代的公司企業(yè)仍主要由批處理驅動。此外,OLAP系統(tǒng)為開發(fā)和分析人員提供了將數(shù)據(jù)想象成n維數(shù)據(jù)集并加以存儲的能力。如果你設想二維數(shù)組和基于兩個索引的查詢,以便基本上與恒定時間一樣高效,但是隨后在此基礎上添加另一個維度,以便可以執(zhí)行實質上是3個或更多因素(比如供應、需求和競爭對手數(shù)量)的查詢,你就可以更高效地分析和預測。然而,構建這些元素是一項費力又高度面向批處理的工作。
圖形數(shù)據(jù)庫幾乎與橫向擴展型NoSQL同一時間面市。許多事物本身不是“關系型”,或者不是基于集合論和關系代數(shù),而是基于父子關系或朋友的朋友關系。一個典例是模型中的產(chǎn)品系列-產(chǎn)品品牌-款型-部件。如果你想知道“我的筆記本電腦搭載什么主板?”,會發(fā)現(xiàn)制造商的采購來源很復雜,光有品牌或型號可能不夠。如果你想知道某產(chǎn)品系列中使用的所有主板,在經(jīng)典(非CTE即通用表表達式)SQL中,你必須遍歷表,并且分多個步驟進行查詢。最初,大多數(shù)圖形數(shù)據(jù)庫根本就不分片。實際上,無需將數(shù)據(jù)實際存儲為圖形,就能完成許多類型的圖形分析。
NoSQL數(shù)據(jù)庫的擴展性確實比Oracle數(shù)據(jù)庫、DB2或SQL Server(它們都基于40年前的一種設計)好得多。然而,每種NoSQL數(shù)據(jù)庫都存在新的限制:
鍵值存儲:沒有比db.get(鍵)更簡單的查詢了。然而,世界上許多數(shù)據(jù)和使用場景無法以這種方式來設計結構。此外,我們其實在談論緩存策略。在任何數(shù)據(jù)庫中,主鍵查詢速度很快。重要的只是內(nèi)存中的數(shù)據(jù)。在理想情況下,它們像哈希圖一樣擴展。然而,如果要跑30趟數(shù)據(jù)庫才能將數(shù)據(jù)放回去或進行任何類型的復雜查詢,這行不通。這些系統(tǒng)現(xiàn)在更常作為緩存實施在其他數(shù)據(jù)庫的前面。(例子:Redis。)
文檔數(shù)據(jù)庫:這種數(shù)據(jù)庫之所以流行起來,是由于它們使用JSON,對象又易于序列化成JSON。這種數(shù)據(jù)庫的第一個版本沒有連接,將整個“實體”放到一個龐大的文檔中有其自身的缺點。沒有事務保證,你還會遇到數(shù)據(jù)完整性問題。今天,一些文檔數(shù)據(jù)庫支持一種不太可靠的事務,但它不是大多數(shù)人習慣的同一種保護級別。而且,即使對簡單查詢而言,這種數(shù)據(jù)庫在延遲方面常常速度很慢,盡管它們就吞吐量而言擴展性更好。(例子:MongoDB和Amazon DocumentDB。)
列存儲:這種數(shù)據(jù)庫的查詢速度與鍵值存儲一樣快,它們可以存儲更復雜的數(shù)據(jù)結構。然而,如果執(zhí)行像跨3個表(RDBMS術語)或3個集合(MongoDB術語)連接這樣的操作,會讓人痛苦不堪。這種數(shù)據(jù)庫確實適合時間序列數(shù)據(jù)(請給我在下午1點至2點出現(xiàn)的所有事務)。
還有其他更深奧的NoSQL數(shù)據(jù)庫。然而,所有這些數(shù)據(jù)庫的共同點是不支持通用數(shù)據(jù)庫慣用語,而且往往專注于“特殊用途”。一些流行的NoSQL數(shù)據(jù)庫(比如MongoDB)編寫了出色的數(shù)據(jù)庫前端和生態(tài)系統(tǒng)工具,因而開發(fā)人員很容易采用它們,但存儲引擎存在嚴重的限制,更不用說彈性和可擴展性方面的限制了。
關系數(shù)據(jù)庫占主導地位的原因之一是,它們有一個通用的工具生態(tài)系統(tǒng)。首先有SQL。雖然數(shù)據(jù)庫方言可能不一樣——如果你是開發(fā)或分析人員,想從SQL Server 6.5升級到Oracle 7,可能不得不修復查詢,并使用“(+)”用于外部連接,但是簡單的切實可行,復雜的很容易轉換。
其次,你有ODBC以及后來的JDBC等。幾乎任何可以連接到一個RDBMS的工具(除非為了管理該RDBMS而專門設計)都可以連接到其他任何RDBMS。有許多人每天連接到RDBMS,并將數(shù)據(jù)倒入到Excel以便分析。我不是指Tableau或其他數(shù)百種工具,而是指“鼻祖”Excel。
NoSQL擯棄了標準。MongoDB不使用SQL作為主要語言。MongoDB的勁敵Couchbase尋找一種查詢語言來取代基于Java的mapreduce框架時,更是創(chuàng)建了一套自己的SQL方言。
標準很重要,無論是為了支持工具生態(tài)系統(tǒng),還是由于許多查詢數(shù)據(jù)庫的人不是開發(fā)人員——他們都知道SQL。