從SQL到NoSQL,數(shù)據(jù)庫還要向何處演進?
在開發(fā)一個應(yīng)用程序時,不可避免要選擇使用SQL還是NoSQL數(shù)據(jù)庫來存儲數(shù)據(jù)。傳統(tǒng)的數(shù)據(jù)庫,即使用SQL(結(jié)構(gòu)化查詢語言)進行查詢的關(guān)系型數(shù)據(jù)庫,是經(jīng)過幾十年來技術(shù)發(fā)展、良好實踐和現(xiàn)實世界壓力測試的產(chǎn)物。它們是為可靠的事務(wù)和臨時查詢而設(shè)計的,是業(yè)務(wù)線應(yīng)用的主力軍。但它們也有一些限制,如嚴格的模式,使它們不太適合于其他類型的應(yīng)用。
NoSQL數(shù)據(jù)庫是針對這些限制而產(chǎn)生的。NoSQL系統(tǒng)存儲和管理數(shù)據(jù)的方式,允許高操作速度,并讓開發(fā)人員有巨大靈活性。許多數(shù)據(jù)庫是由谷歌、亞馬遜、雅虎和Facebook等公司開發(fā)的,它們尋求更好的方式來存儲內(nèi)容或處理大型網(wǎng)站的數(shù)據(jù)。與SQL數(shù)據(jù)庫不同,許多NoSQL數(shù)據(jù)庫可以在數(shù)百或數(shù)千臺服務(wù)器上進行橫向擴展。
不過,NoSQL的優(yōu)勢并不是沒有代價的。NoSQL系統(tǒng)傾向于速度和可擴展性,而不是SQL數(shù)據(jù)庫所承諾的可靠事務(wù)背后的ACID屬性。與圍繞SQL建立的數(shù)十年的機構(gòu)知識相比,在NoSQL系統(tǒng)中用于處理數(shù)據(jù)的隱喻也是相對較新的。
SQL和NoSQL數(shù)據(jù)庫提供了不同的權(quán)衡。雖然它們在特定項目的背景下可能會有競爭,例如,為不同應(yīng)用會面臨二選一的情況,但它們在更大范圍內(nèi)是互補的,每一種都適合于不同的使用情況。是選擇SQL還是NoSQL并不是絕對的,要根據(jù)場景需求選合適的。
NoSQL與SQL
SQL和NoSQL之間的根本區(qū)別并不那么復雜。對于如何存儲和檢索數(shù)據(jù),兩者都有不同的理念。
對于SQL數(shù)據(jù)庫,所有數(shù)據(jù)都有一個固有的結(jié)構(gòu)。像Microsoft SQL Server、MySQL、PostgreSQL或Oracle數(shù)據(jù)庫這樣的傳統(tǒng)數(shù)據(jù)庫使用一個模式--對插入數(shù)據(jù)庫的數(shù)據(jù)如何組成的正式定義。例如,一個表中的某一列可能被限制為只能是整數(shù)。因此,記錄在該列中的數(shù)據(jù)將有很高的規(guī)范化程度。SQL數(shù)據(jù)庫的嚴格模式也使得對數(shù)據(jù)進行聚合變得相對容易,例如,使用SQL JOIN命令將兩個表的數(shù)據(jù)合并。
在NoSQL中,數(shù)據(jù)可以以無模式或自由的方式存儲。任何數(shù)據(jù)都可以存儲在任何記錄中。在NoSQL數(shù)據(jù)庫中,你會發(fā)現(xiàn)四種常見的數(shù)據(jù)存儲模式,這導致了四種常見的NoSQL系統(tǒng)類型。
- 文檔數(shù)據(jù)庫(如MongoDB)。插入的數(shù)據(jù)以無模式的JSON結(jié)構(gòu)或“文檔”的形式存儲,其中的數(shù)據(jù)可以是任何東西,從整數(shù)到字符串再到自由格式的文本。沒有必要指定JSON文檔將包含哪些字段(如果有的話)。
- 鍵值存儲(如Redis)。自由格式的值,從簡單的整數(shù)或字符串到復雜的JSON文檔,都可以通過鍵(比如字符串)在數(shù)據(jù)庫中訪問。
- 寬列存儲(如 Cassandra)。數(shù)據(jù)被存儲在列中,而不是像傳統(tǒng)SQL系統(tǒng)存儲在行。任何數(shù)量的列(以及許多不同類型的數(shù)據(jù))都可以根據(jù)查詢或數(shù)據(jù)視圖的需要進行分組或聚合。
- 圖數(shù)據(jù)庫(如Neo4j)。數(shù)據(jù)被表示為實體及其關(guān)系的網(wǎng)絡(luò)或圖形,其中圖中的每個節(jié)點是一個自由形式的數(shù)據(jù)塊。
無模式的數(shù)據(jù)存儲在以下情況下是有用的。
- 你想快速訪問數(shù)據(jù),你更關(guān)心訪問的速度和簡單性,而不是可靠的事務(wù)或一致性。
- 你正在存儲大量的數(shù)據(jù),你不想把自己鎖定在一個模式中,因為以后改變模式可能是緩慢和痛苦的。
- 你正在從一個或多個來源接收非結(jié)構(gòu)化數(shù)據(jù),你想保持數(shù)據(jù)的原始格式以獲得最大的靈活性。
- 你想把數(shù)據(jù)存儲在一個分層結(jié)構(gòu)中,但你希望這些分層結(jié)構(gòu)由數(shù)據(jù)本身來描述,而不是外部模式。NoSQL允許數(shù)據(jù)隨意地自我引用,該方式對于SQL數(shù)據(jù)庫來說更為復雜,難以模仿。
查詢NoSQL數(shù)據(jù)庫
關(guān)系型數(shù)據(jù)庫使用的結(jié)構(gòu)化查詢語言提供了一種統(tǒng)一的方式,在存儲和檢索數(shù)據(jù)時與服務(wù)器通信。SQL語法是高度標準化的,所以盡管各個數(shù)據(jù)庫可能會以不同的方式處理某些操作(例如,窗口函數(shù)),但基本原理仍然是相同的。
相比之下,每個NoSQL數(shù)據(jù)庫往往都有自己的語法來查詢和管理數(shù)據(jù)。例如,CouchDB使用JSON形式的請求,通過HTTP發(fā)送,以創(chuàng)建或檢索其數(shù)據(jù)庫中的文檔。MongoDB通過二進制協(xié)議,以命令行接口或語言庫的方式發(fā)送JSON對象。
一些NoSQL產(chǎn)品可以使用類似SQL的語法來處理數(shù)據(jù),但只是在有限的范圍內(nèi)。例如,Apache Cassandra,一個廣泛的列存儲,有自己的類似SQL的語言,Cassandra查詢語言(CQL)。CQL的一些語法是直接來自于SQL的手冊,比如SELECT或INSERT關(guān)鍵字。但在Cassandra中沒有執(zhí)行JOIN或子查詢的本地方法,因此相關(guān)的關(guān)鍵字在CQL中并不存在。
無共享shared-nothing架構(gòu)
NoSQL系統(tǒng)常見的一個設(shè)計選擇是“shared-nothing”架構(gòu)。在一個無共享的設(shè)計中,集群中的每個服務(wù)器節(jié)點都獨立于其他節(jié)點運行。系統(tǒng)不需要從其他節(jié)點獲得共識來返回數(shù)據(jù)給客戶端。查詢速度很快,因為它們可以從最近的或最方便的節(jié)點返回。
無共享系統(tǒng)的另一個優(yōu)點是彈性和向外擴展。向外擴展集群非常容易,只需旋轉(zhuǎn)集群中的新節(jié)點并等待它們與其他節(jié)點同步即可。如果一個NoSQL節(jié)點宕機,集群中的其他服務(wù)器將繼續(xù)運行。即使服務(wù)請求的節(jié)點減少,所有數(shù)據(jù)仍然可用。
請注意,無共享的設(shè)計并不是NoSQL數(shù)據(jù)庫所獨有的。許多傳統(tǒng)的SQL系統(tǒng)可以以無共享的方式設(shè)置,如MySQL,盡管這通常涉及到犧牲整個集群的一致性以獲得性能。
NoSQL的局限性
如果NoSQL提供了如此多的自由和靈活性,為什么不完全放棄SQL?答案很簡單,許多應(yīng)用仍然需要SQL數(shù)據(jù)庫所提供的各種約束、一致性和保障措施。在這些情況下,NoSQL的一些“優(yōu)勢”可能會變成劣勢。其他的限制來自于NoSQL系統(tǒng)缺乏某些在SQL領(lǐng)域中本應(yīng)有的功能。
(1) 無模式(No schema)
即使你接收的是自由格式的數(shù)據(jù),你也幾乎總是需要對數(shù)據(jù)施加約束,以使其有用。對于NoSQL,施加約束涉及到將責任從數(shù)據(jù)庫轉(zhuǎn)移到應(yīng)用開發(fā)者身上。例如,開發(fā)者可以通過一個對象關(guān)系映射系統(tǒng)(或稱ORM)強加結(jié)構(gòu)。但如果你想讓模式與數(shù)據(jù)本身共存,NoSQL通常不支持這種做法。
一些NoSQL解決方案為數(shù)據(jù)提供了可選的數(shù)據(jù)類型和驗證機制。例如,Apache Cassandra有一系列的本地數(shù)據(jù)類型,讓人想起傳統(tǒng)SQL中的那些數(shù)據(jù)類型。
(2) 最終一致性
NoSQL系統(tǒng)提供了強一致性或即時一致性的選擇,以獲得更好的可用性和性能。傳統(tǒng)的數(shù)據(jù)庫確保操作是原子的(事務(wù)的所有部分都成功,或者沒有一個成功)、一致的(所有用戶都有相同的數(shù)據(jù)視圖)、隔離的(事務(wù)不競爭)和持久的(一旦完成,它們將不受服務(wù)器故障的影響)。
這四個屬性,統(tǒng)稱為ACID,在NoSQL系統(tǒng)中可以用不同的方式處理。你可以選擇最終一致性,而不是要求整個集群的強一致性,這必然會延遲對請求的響應(yīng),允許服務(wù)請求,而無需等待最新的寫入復制到集群的其它節(jié)點。插入集群的數(shù)據(jù)最終在各處都是可用的,但不能保證任何時候可用。
對于一些NoSQL系統(tǒng),你可以在一致性和速度之間選擇一個折中方案,不同的產(chǎn)品有不同的方案。例如,微軟的Azure Cosmos DB可以讓你選擇每個請求的一致性級別,所以你可以選擇適合你的。事務(wù)語義,在SQL系統(tǒng)中保證事務(wù)中的所有步驟(例如執(zhí)行銷售和減少庫存)要么完成,要么回滾,在一些NoSQL系統(tǒng)中也有,例如MongoDB。
(3) NoSQL的鎖定
大多數(shù)NoSQL系統(tǒng)在概念上是相似的,但實現(xiàn)方式不同。每個系統(tǒng)都有自己的隱喻和機制,用于數(shù)據(jù)的查詢和管理。
這樣做的一個副作用是應(yīng)用邏輯和數(shù)據(jù)庫之間可能存在高度的耦合。如果你選擇一個NoSQL系統(tǒng)并堅持使用它,這種耦合性并沒有什么壞處,但如果你在未來更換系統(tǒng),它就會成為一個絆腳石。
如果你從MongoDB遷移到CouchDB(或者相反),你需要做的不僅僅是遷移數(shù)據(jù)。還必須駕馭數(shù)據(jù)訪問和編程隱喻之間的差異。換句話說,你必須重寫應(yīng)用程序中訪問數(shù)據(jù)庫的部分。
(4) NoSQL技能
NoSQL的另一個缺點是相對缺乏專業(yè)知識。傳統(tǒng)SQL人才的市場相當大,而NoSQL技能的市場卻剛剛起步。
作為參考,Indeed.com報告稱,截至2022年,傳統(tǒng)SQL數(shù)據(jù)庫(MySQL、微軟SQL Server、Oracle數(shù)據(jù)庫等)的職位數(shù)量仍然高于MongoDB、Couchbase和Cassandra的職位數(shù)量。對NoSQL專業(yè)知識的需求仍然只是SQL技能市場的一小部分。
合并SQL和NoSQL
未來,隨著時間的推移,SQL和NoSQL系統(tǒng)之間的一些差異會消失?,F(xiàn)在已經(jīng)有許多SQL數(shù)據(jù)庫接受JSON文檔作為原生數(shù)據(jù)類型,并可以對該數(shù)據(jù)進行查詢。一些數(shù)據(jù)庫甚至有對JSON數(shù)據(jù)施加約束的本地方法,因此其處理方式與傳統(tǒng)的行和列數(shù)據(jù)一樣嚴格。
另一方面,NoSQL數(shù)據(jù)庫不僅增加了類似SQL的查詢語言,還增加了傳統(tǒng)SQL數(shù)據(jù)庫的其他功能,比如MongoDB的ACID屬性。
一個可能的路徑是,未來幾代數(shù)據(jù)庫以及當前數(shù)據(jù)庫系統(tǒng)的未來版本將跨越這些范式,同時提供SQL和NoSQL功能,有助于使數(shù)據(jù)庫世界不再支離破碎。例如,微軟的Azure Cosmos DB在底層使用了一套基元,可以互換地再現(xiàn)兩種系統(tǒng)的行為。谷歌云Spanner將SQL的強一致性與NoSQL系統(tǒng)的水平可擴展性相結(jié)合。
不過,純SQL和純NoSQL系統(tǒng)仍將在未來很多年占有一席之地。在設(shè)計靈活性、水平擴展性和高可用性比強讀一致性和其他SQL數(shù)據(jù)庫常見的保障措施更重要的情況下,可以考慮使用NoSQL。對于許多應(yīng)用來說,這些保障措施很可能值得用來交換NoSQL所提供的東西。
對于許多應(yīng)用程序來說,以NoSQL的特有優(yōu)勢來那些換保障措施是值得。