Apache Cassandra static column 介紹與實戰

假設咱們有這樣的場景:咱們想在 Cassandra 中使用一張表記錄用戶基本信息(好比 email、密碼等)以及用戶狀態更新。咱們知道,用戶的基本信息通常不多會變更,可是狀態會常常變化,若是每次狀態更新都把用戶基本信息都加進去,勢必會讓費大量的存儲空間。爲了解決這種問題,Cassandra 引入了 static column。同一個 partition key 中被聲明爲 static 的列只有一個值的,也就是隻存儲一份。前端

定義 static column

在表中將某個列定義爲 STATIC 很簡單,只須要在列的最後面加上 STATIC 關鍵字,具體以下:oop

CREATE TABLE "iteblog_users_with_status_updates" (
  "username" text,
  "id" timeuuid,
  "email" text STATIC,
  "encrypted_password" blob STATIC,
  "body" text,
  PRIMARY KEY ("username", "id")
);

iteblog_users_with_status_updates 表中咱們將 email 和 encrypted_password 兩個字段設置爲 STATIC 了,這意味着同一個 username 只會有一個 email 和 encrypted_password 。ui

注意,不是任何表都支持給列加上 STATIC 關鍵字的,靜態列有如下限制。spa

一、若是表沒有定義 Clustering columns(又稱 Clustering key),這種狀況是不能添加靜態列的。以下:code

cqlsh:iteblog_keyspace> CREATE TABLE "iteblog_users_with_status_updates_invalid" (
                    ...   "username" text,
                    ...   "id" timeuuid,
                    ...   "email" text STATIC,
                    ...   "encrypted_password" blob STATIC,
                    ...   "body" text,
                    ...   PRIMARY KEY ("username")
                    ... );
InvalidRequest: Error from server: code=2200 [Invalid query] message="Static columns are only useful (and thus allowed) if the table has at least one clustering column"

iteblog_users_with_status_updates_invalid 表只有 PRIMARY KEY,沒有定義 clustering column,不支持建立 Static columns。這是由於靜態列在同一個 partition key 存在多行的狀況下才能達到最優狀況,並且行數越多效果也好。可是若是沒有定義 clustering column,相同 PRIMARY KEY 的數據在同一個分區裏面只存在一行數據,本質上就是靜態的,因此不必支持靜態列。server

二、若是建表的時候指定了 COMPACT STORAGE,這時候也不容許存在靜態列:blog

cqlsh:iteblog_keyspace> CREATE TABLE "iteblog_users_with_status_updates_invalid" (
                    ...   "username" text,
                    ...   "id" timeuuid,
                    ...   "email" text STATIC,
                    ...   "encrypted_password" blob STATIC,
                    ...   "body" text,
                    ...   PRIMARY KEY ("username", "id")
                    ... )WITH COMPACT STORAGE;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Static columns are not supported in COMPACT STORAGE tables"

三、若是列是 partition key/Clustering columns 的一部分,那麼這個列不能說明爲靜態列:hadoop

cqlsh:iteblog_keyspace> CREATE TABLE "iteblog_users_with_status_updates_invalid" (
                    ...   "username" text,
                    ...   "id" timeuuid STATIC,
                    ...   "email" text STATIC,
                    ...   "encrypted_password" blob STATIC,
                    ...   "body" text,
                    ...   PRIMARY KEY ("username", "id")
                    ... );
InvalidRequest: Error from server: code=2200 [Invalid query] message="Static column id cannot be part of the PRIMARY KEY"
cqlsh:iteblog_keyspace> CREATE TABLE "iteblog_users_with_status_updates_invalid" (
                    ...   "username" text,
                    ...   "id" timeuuid,
                    ...   "email" text STATIC,
                    ...   "encrypted_password" blob STATIC,
                    ...   "body" text,
                    ...   PRIMARY KEY (("username", "id"), email)
                    ... );
InvalidRequest: Error from server: code=2200 [Invalid query] message="Static column email cannot be part of the PRIMARY KEY"

給靜態列的表插入數據

含有靜態列的表插入數據和正常表相似,好比咱們如今往 iteblog_users_with_status_updates 導入數據:get

cqlsh:iteblog_keyspace> INSERT INTO "iteblog_users_with_status_updates"
                    ... ("username", "id", "email", "encrypted_password", "body")
                    ... VALUES (
                    ...   'iteblog',
                    ...   NOW(),
                    ...   'iteblog_hadoop@iteblog.com',
                    ...   0x877E8C36EFA827DBD4CAFBC92DD90D76,
                    ...   'Learning Cassandra!'
                    ... );
cqlsh:iteblog_keyspace> select username, email, encrypted_password, body from iteblog_users_with_status_updates;
 
 username | email                      | encrypted_password                 | body
----------+----------------------------+------------------------------------+---------------------
  iteblog | iteblog_hadoop@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76 | Learning Cassandra!

(1 rows)

咱們成功的插入一條數據了。可是上面的插入語句作了兩件事:it

  • 全部 username 爲 iteblog 數據中的 email 和 encrypted_password 都被設置爲 iteblog_hadoop@iteblog.com 和 0x877e8c36efa827dbd4cafbc92dd90d76 了。
  • 在 iteblog 所在的分區中新增了 body 內容爲 Learning Cassandra! 的記錄。

如今咱們再往表中插入一條數據,以下:

cqlsh:iteblog_keyspace> INSERT INTO "iteblog_users_with_status_updates"
                    ... ("username", "id", "body")
                    ... VALUES ('iteblog', NOW(), 'I love Cassandra!');
cqlsh:iteblog_keyspace> select username, email, encrypted_password, body from iteblog_users_with_status_updates;
 
 username | email                      | encrypted_password                 | body
----------+----------------------------+------------------------------------+---------------------
  iteblog | iteblog_hadoop@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76 | Learning Cassandra!
  iteblog | iteblog_hadoop@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76 |   I love Cassandra!
 
(2 rows)
cqlsh:iteblog_keyspace>

能夠看到,此次插入數據的時候,咱們並無指定 email 和 encrypted_password,可是從查詢結果能夠看出,新增長的行 email 和 encrypted_password 的值和以前是同樣的!

如今因爲某些緣由,用戶修改了本身的 email,咱們來看看會發生什麼事:

cqlsh:iteblog_keyspace> UPDATE iteblog_users_with_status_updates SET email = 'iteblog@iteblog.com'
                    ... WHERE username = 'iteblog';
cqlsh:iteblog_keyspace> select username, email, encrypted_password, body from iteblog_users_with_status_updates;
 
 username | email               | encrypted_password                 | body
----------+---------------------+------------------------------------+---------------------
  iteblog | iteblog@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76 | Learning Cassandra!
  iteblog | iteblog@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76 |   I love Cassandra!
 
(2 rows)

從上面查詢這輸出的結果能夠看出, username 爲 iteblog 的 email 所有修改爲同樣的了!這就是靜態列的強大之處。

如今表中存在了用戶的郵箱和密碼等信息,若是咱們前端作了個頁面支持用戶修改本身的郵箱和密碼,這時候咱們的後臺系統須要獲取到現有的郵箱和密碼,具體以下:

cqlsh:iteblog_keyspace> SELECT "username", "email", "encrypted_password"
                    ... FROM "iteblog_users_with_status_updates"
                    ... WHERE "username" = 'iteblog';
 
 username | email               | encrypted_password
----------+---------------------+------------------------------------
  iteblog | iteblog@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76
  iteblog | iteblog@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76
 
(2 rows)

能夠看出,表中有多少行 username 爲 iteblog 的數據將會輸出多少行郵箱和密碼,這確定不是咱們想要的。這時候咱們能夠在查詢的時候加上 DISTINCT 關鍵字,以下:

cqlsh:iteblog_keyspace> SELECT DISTINCT "username", "email", "encrypted_password"
                    ... FROM "iteblog_users_with_status_updates"
                    ... WHERE "username" = 'iteblog';
 
 username | email               | encrypted_password
----------+---------------------+------------------------------------
  iteblog | iteblog@iteblog.com | 0x877e8c36efa827dbd4cafbc92dd90d76
 
(1 rows)

這樣無論表中有多少行 username 爲 iteblog 的數據,最終都會顯示一行數據。注意,雖然咱們加了 DISTINCT 關鍵字,可是 Cassandra 並非將 username 爲 iteblog 的數據所有拿出來,而後再去重的,由於靜態列原本在底層就存儲了一份,因此不必去重。

靜態列的意義

到這裏,咱們已經瞭解了 Cassandra 中靜態列的建立、使用等。那靜態列有什麼意義呢?由於 Cassandra 中是不支持 join 的,靜態列至關於把兩張表進行了 join 操做。

那何時建議使用靜態列呢?若是兩張表關聯度很大,並且咱們常常須要同時查詢這兩張表,那這時候就能夠考慮使用靜態列了。



本文做者:明惠

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索