全面比較非關(guān)系型數(shù)據(jù)庫(kù)Cassandra與RDBMS的設(shè)計(jì)差別
Cassandra是一個(gè)混合型的非關(guān)系型數(shù)據(jù)庫(kù),是一個(gè)網(wǎng)絡(luò)社交云計(jì)算方面理想的數(shù)據(jù)庫(kù)。Cassandra的模型和查詢方式與RDBMS有很多的不同,記住這些差異非常重要。本文我們主要對(duì)Cassandra和RDBMS的設(shè)計(jì)差別進(jìn)行全面的比較,接下來就讓我們來一起了解一下吧。
沒有查詢語言
SQL是關(guān)系型數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)查詢語言,Cassandra卻沒有查詢語言。不過Cassandra確實(shí)也有自己的RPC序列化機(jī)制,Thrift。通過Thrift API,用戶可以訪問其中的數(shù)據(jù)。
沒有引用完整性
Cassandra沒有引用完整性的概念,因而沒有join的概念。在關(guān)系型數(shù)據(jù)庫(kù)中,你可以在一個(gè)表中指定一個(gè)外部鍵值, 以此引用另一個(gè)表中記錄的主鍵。但是,Cassandra并沒有提供這個(gè)功能。存儲(chǔ)其他表中的相關(guān)ID是一個(gè)通用需求,這仍然是被支持的,但Cassandra里沒有級(jí)聯(lián)刪除這樣的概念。
第二索引
第二索引確實(shí)是一個(gè)有用的功能,比如你需要找到具有某個(gè)屬性的酒店的唯一ID,在關(guān)系型數(shù)據(jù)庫(kù)里,可能這么查詢:
SELECT hotelID FROM Hotel WHERE name = 'Clarion Midtown';
當(dāng)你知道酒店的名字卻不知道ID的時(shí)候,肯定想這么查詢這個(gè)酒店。關(guān)系型數(shù)據(jù)庫(kù)如果接到這個(gè)查詢,會(huì)進(jìn)行一個(gè)全表掃描,檢查每行的name列,查找所需要的名字。如果表很大,這種查詢可能會(huì)很慢。對(duì)這種情況,關(guān)系型數(shù)據(jù)庫(kù)的解決方案就是為這列建一個(gè)索引,相當(dāng)于這部分?jǐn)?shù)據(jù)的一個(gè)副本,來幫助更快地檢索數(shù)據(jù)。因?yàn)镠otelID已經(jīng)是一個(gè)主鍵約束了,主鍵會(huì)自動(dòng)進(jìn)行索引,也就是主索引,所以,對(duì)name列建立的索引自然就是第二索引,目前Cassandra仍然不支持第二索引。
要在Cassandra中做到同樣的事情,需要?jiǎng)?chuàng)建另一個(gè)列族來存儲(chǔ)查詢信息。你可以創(chuàng)建一個(gè)列族來存儲(chǔ)酒店名,并將它們映射到酒店的ID。第二列族實(shí)際上起到一個(gè)顯式的第二索引的作用。
第二索引目前正在被加入到Cassandra 0.7之中來,允許為列值建立索引。所以,如果你希望找到所有居住在指定城市的用戶,第二索引的支持將會(huì)讓你不必費(fèi)力手工建立第二索引列族了。
排序成為一種設(shè)計(jì)決策
在RDBMS中,可以在查詢中使用ORDER BY來輕松改變返回記錄的順序。默認(rèn)的排序方法確實(shí)是不可配置的;默認(rèn)情況下,記錄按照它們寫入的順序被讀出。如果希望改變順序,只要改變查詢語句即可,而且可以對(duì)任意一組列進(jìn)行排序。但在Cassandra之中,排序就不同了,它變成了一個(gè)設(shè)計(jì)決策。列族的定義中包含一個(gè)CompareWith配置元素,這個(gè)配置指定了行在讀出的時(shí)候按照什么方式排序,它在查詢的時(shí)候是無法重新配置的。
RDBMS限制你只能基于存儲(chǔ)在列中的數(shù)據(jù)類型來進(jìn)行排序,但Cassandra存儲(chǔ)的數(shù)據(jù)是字節(jié)數(shù)組,所以這種用指定數(shù)據(jù)類型排序的方法是行不通的。不過,你能做的是把列當(dāng)作幾種可排序的類型之一(ASCII、LONG、integer、TimestampUUID、字典排序等)。如果需要,你還可以使用自己實(shí)現(xiàn)的比較器來進(jìn)行排序。此外,Cassandra里沒有SQL里的ORDER BY和GROUP BY語句。
反范式化
在關(guān)系型數(shù)據(jù)庫(kù)設(shè)計(jì)中,我們經(jīng)常強(qiáng)調(diào)范式化的重要性。但是當(dāng)使用Cassandra時(shí),這就不是一個(gè)優(yōu)點(diǎn)了,因?yàn)橹挥挟?dāng)數(shù)據(jù)模型是反范式化的時(shí)候,它的性能才是***的。實(shí)際上,很多公司最終都會(huì)將關(guān)系型數(shù)據(jù)庫(kù)反范式化,這主要有兩個(gè)原因。其一是性能原因,當(dāng)他們?cè)谄涠嗄攴e累的海量有價(jià)值的數(shù)據(jù)上進(jìn)行大量的join操作的時(shí)候,無法得到所需的性能,于是就按照已知的查詢內(nèi)容來反范式化數(shù)據(jù)庫(kù)以優(yōu)化查詢。這種方法最終可以工作,但和關(guān)系型數(shù)據(jù)庫(kù)的設(shè)計(jì)初衷相悖,最終引發(fā)的問題就是,在這種條件下,使用關(guān)系型數(shù)據(jù)庫(kù)是否還是***手段。
關(guān)系型數(shù)據(jù)庫(kù)進(jìn)行反范式化的第二個(gè)原因是業(yè)務(wù)文檔結(jié)構(gòu)有時(shí)需要留存。也就是說,你有一個(gè)外圍表,引用了很多的外部表,表的數(shù)據(jù)可能會(huì)隨時(shí)間發(fā)生變化,但你也需要以快照形式保存外圍文檔的歷史。常見的一個(gè)例子是收款信息。你已經(jīng)有客戶和產(chǎn)品表了,而且認(rèn)為可以在收款信息里引用這些表。但是實(shí)際不應(yīng)該這么做,因?yàn)榭蛻艉蛢r(jià)格信息都可能發(fā)生變化,那時(shí)你就會(huì)丟失收款信息的完整性了,因?yàn)檫@些表的變動(dòng)似乎在收款時(shí)也發(fā)生了,這可能會(huì)影響到審計(jì)、報(bào)告,甚至是違法的,還可能引發(fā)其他問題。
在關(guān)系型數(shù)據(jù)庫(kù)里, 反范式化會(huì)破壞Codd的范式, 我們需要盡力避免。但在Cassandra中,反范式化卻正好合乎規(guī)則。它在數(shù)據(jù)模型很簡(jiǎn)單時(shí)并不必要,但也不需要害怕它。
重點(diǎn)在于,首先對(duì)數(shù)據(jù)建模、然后再寫查詢的方法不再適用了。Cassandra中,應(yīng)該先定義好查詢,并圍繞查詢來組織數(shù)據(jù)??紤]一下應(yīng)用使用的最基本的查詢路徑,之后根據(jù)查詢路徑來構(gòu)建所需要的列族就可以了。
批評(píng)者們認(rèn)為這是個(gè)非常嚴(yán)重的問題。不過在設(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候能夠考慮應(yīng)用如何查詢也并非沒有道理,實(shí)際上,一般在關(guān)系型數(shù)據(jù)庫(kù)里也是這么做的。如果不能正確預(yù)期查詢方式,那么不論是在Cassandra里還是在關(guān)系型數(shù)據(jù)庫(kù)里,都會(huì)遇到問題。當(dāng)然,查詢方式可能會(huì)隨著時(shí)間推移而改變,那么就不得不更新數(shù)據(jù)了。不過這和在關(guān)系型數(shù)據(jù)庫(kù)里定義表時(shí)犯錯(cuò)或需要新的附加表也沒什么區(qū)別。
關(guān)于Cassandra與RDBMS的比較就介紹到這里了,希望本次的介紹能夠給您帶來一些收獲!
【編輯推薦】






