假设咱们有这样的场景:咱们想在 Cassandra 中使用一张表记录用户基本信息(好比 email、密码等)以及用户状态更新。咱们知道,用户的基本信息通常不多会变更,可是状态会常常变化,若是每次状态更新都把用户基本信息都加进去,势必会让费大量的存储空间。为了解决这种问题,Cassandra 引入了 static column。同一个 partition key 中被声明为 static 的列只有一个值的,也就是只存储一份。前端
在表中将某个列定义为 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
如今咱们再往表中插入一条数据,以下:
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 操做。
那何时建议使用静态列呢?若是两张表关联度很大,并且咱们常常须要同时查询这两张表,那这时候就能够考虑使用静态列了。
本文为云栖社区原创内容,未经容许不得转载。