Cassandra與RDBMS的設計差別

turingbooks發表於2020-04-07


Cassandra的模型和查詢方式與RDBMS有很多的不同,記住這些差異非常重要。

  • 沒有查詢語言

SQL是關係型資料庫的標準查詢語言,Cassandra卻沒有查詢語言。不過Cassandra確實也有自己的RPC序列化機制,Thrift。通過Thrift API,使用者可以訪問其中的資料。

  • 沒有引用完整性

Cassandra沒有引用完整性的概念,因而沒有join的概念。在關係型資料庫中,你可以在一個表中指定一個外部鍵值, 以此引用另一個表中記錄的主鍵。但是,Cassandra並沒有提供這個功能。儲存其他表中的相關ID是一個通用需求,這仍然是被支援的,但Cassandra裡沒有級聯刪除這樣的概念。

  • 第二索引

第二索引確實是一個有用的功能,比如你需要找到具有某個屬性的酒店的唯一ID,在關係型資料庫裡,可能這麼查詢:

SELECT hotelID FROM Hotel WHERE name = 'Clarion Midtown';

當你知道酒店的名字卻不知道ID的時候,肯定想這麼查詢這個酒店。關係型資料庫如果接到這個查詢,會進行一個全表掃描,檢查每行的name列,查詢所需要的名字。如果表很大,這種查詢可能會很慢。對這種情況,關係型資料庫的解決方案就是為這列建一個索引,相當於這部分資料的一個副本,來幫助更快地檢索資料。因為HotelID已經是一個主鍵約束了,主鍵會自動進行索引,也就是主索引,所以,對name列建立的索引自然就是第二索引,目前Cassandra仍然不支援第二索引。

要在Cassandra中做到同樣的事情,需要建立另一個列族來儲存查詢資訊。你可以建立一個列族來儲存酒店名,並將它們對映到酒店的ID。第二列族實際上起到一個顯式的第二索引的作用。

第二索引目前正在被加入到Cassandra 0.7之中來,允許為列值建立索引。所以,如果你希望找到所有居住在指定城市的使用者,第二索引的支援將會讓你不必費力手工建立第二索引列族了。

  • 排序成為一種設計決策

在RDBMS中,可以在查詢中使用ORDER BY來輕鬆改變返回記錄的順序。預設的排序方法確實是不可配置的;預設情況下,記錄按照它們寫入的順序被讀出。如果希望改變順序,只要改變查詢語句即可,而且可以對任意一組列進行排序。但在Cassandra之中,排序就不同了,它變成了一個設計決策。列族的定義中包含一個CompareWith配置元素,這個配置指定了行在讀出的時候按照什麼方式排序,它在查詢的時候是無法重新配置的。

RDBMS限制你只能基於儲存在列中的資料型別來進行排序,但Cassandra儲存的資料是位元組陣列,所以這種用指定資料型別排序的方法是行不通的。不過,你能做的是把列當作幾種可排序的型別之一(ASCII、LONG、integer、TimestampUUID、字典排序等)。如果需要,你還可以使用自己實現的比較器來進行排序。

此外,Cassandra裡沒有SQL裡的ORDER BY和GROUP BY語句。有一個查詢的型別稱為SliceRange,在第4章裡會介紹到,它類似於ORDER BY,因為它允許翻轉。

  • 反正規化化

在關係型資料庫設計中,我們經常強調正規化化的重要性。但是當使用Cassandra時,這就不是一個優點了,因為只有當資料模型是反正規化化的時候,它的效能才是最好的。實際上,很多公司最終都會將關係型資料庫反正規化化,這主要有兩個原因。其一是效能原因,當他們在其多年積累的海量有價值的資料上進行大量的join操作的時候,無法得到所需的效能,於是就按照已知的查詢內容來反正規化化資料庫以優化查詢。這種方法最終可以工作,但和關係型資料庫的設計初衷相悖,最終引發的問題就是,在這種條件下,使用關係型資料庫是否還是最佳手段。

關係型資料庫進行反正規化化的第二個原因是業務文件結構有時需要留存。也就是說,你有一個外圍表,引用了很多的外部表,表的資料可能會隨時間發生變化,但你也需要以快照形式儲存外圍文件的歷史。常見的一個例子是收款資訊。你已經有客戶和產品表了,而且認為可以在收款資訊裡引用這些表。但是實際不應該這麼做,因為客戶和價格資訊都可能發生變化,那時你就會丟失收款資訊的完整性了,因為這些表的變動似乎在收款時也發生了,這可能會影響到審計、報告,甚至是違法的,還可能引發其他問題。

在關係型資料庫裡, 反正規化化會破壞Codd的正規化, 我們需要盡力避免。但在Cassandra中,反正規化化卻正好合乎規則。它在資料模型很簡單時並不必要,但也不需要害怕它。

重點在於,首先對資料建模、然後再寫查詢的方法不再適用了。Cassandra中,應該先定義好查詢,並圍繞查詢來組織資料。考慮一下應用使用的最基本的查詢路徑,之後根據查詢路徑來構建所需要的列族就可以了。

批評者們認為這是個非常嚴重的問題。不過在設計資料庫的時候能夠考慮應用如何查詢也並非沒有道理,實際上,一般在關係型資料庫裡也是這麼做的。如果不能正確預期查詢方式,那麼不論是在Cassandra裡還是在關係型資料庫裡,都會遇到問題。當然,查詢方式可能會隨著時間推移而改變,那麼就不得不更新資料了。不過這和在關係型資料庫裡定義表時犯錯或需要新的附加表也沒什麼區別。

有一篇關於Cloudkick如何使用Cassandra儲存效能監控指標資料的文章,可以在這裡閱讀:點選開啟連結

相關文章