Cassandra 的数据结构

Cassandra的数据结构

Cassandra的Column Family具有类似于以下二维映射的结构。

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

上述的 RowKey 在 CQL 中被称为分区键(Partition Key),根据这个分区键将数据分配到节点上。
此外,在 CQL 中,主键且不是分区键的 ColumnKey 被称为聚簇列(Clustering Column)(顾名思义,它用于在某个分区中创建键值块)。

当在单个分区上发生大量的读写操作时,会导致特定节点的负载增加。为了考虑负载均衡,需要确定分区键。

通过CQL创建的数据的物理结构

创建以下类型的表,并插入数据。

CREATE KEYSPACE key_space_test WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };

use key_space_test;

CREATE TABLE testtable (
  pkey1 text,
  pkey2 text,
  skey  int,
  value text,
  cvalue map<text,text>,
  PRIMARY KEY ((pkey1, pkey2), skey)
) WITH CLUSTERING ORDER BY (skey DESC);


INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_1', 100, {'hoge': 'fuga'}, 'value11_100');

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_2', 'pkey2_1', 200, {'hoge': 'fuga'}, 'value21_200');

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_2', 101, {'hoge1': 'fuga1'}, 'value12_101');

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_3', 102, {'hoge1': 'fuga1'}), 'value13_102';

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_1', 101, {'hoge1': 'fuga1'}, 'value11_101');

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_1', 103, {'hoge1': 'fuga1'}, 'value11_103');

INSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
 VALUES('pkey1_1', 'pkey2_1', 102, {'hoge1': 'fuga1'}, 'value11_102');

NSERT INTO testtable (pkey1, pkey2, skey, cvalue, value)
  VALUES('pkey1_1', 'pkey2_1', 12, {'hoge': 'fuga'}, 'value11_12')
cqlsh> use key_space_test ;
cqlsh:key_space_test> select * from testtable;

 pkey1   | pkey2   | skey | cvalue             | value
---------+---------+------+--------------------+-------------
 pkey1_1 | pkey2_1 |  103 | {'hoge1': 'fuga1'} | value11_103
 pkey1_1 | pkey2_1 |  102 | {'hoge1': 'fuga1'} | value11_102
 pkey1_1 | pkey2_1 |  101 | {'hoge1': 'fuga1'} | value11_101
 pkey1_1 | pkey2_1 |  100 |   {'hoge': 'fuga'} | value11_100
 pkey1_1 | pkey2_1 |   12 |   {'hoge': 'fuga'} |  value11_12
 pkey1_2 | pkey2_1 |  200 |   {'hoge': 'fuga'} | value21_200
 pkey1_1 | pkey2_3 |  102 | {'hoge1': 'fuga1'} | value13_102
 pkey1_1 | pkey2_2 |  101 | {'hoge1': 'fuga1'} | value12_101

(7 rows)

如果使用cassandra-cli查看上述状态,会显示如下信息。

[default@unknown] use key_space_test;
Authenticated to keyspace: key_space_test
[default@key_space_test] list testtable;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: pkey2_1:pkey2_1
-------------------
RowKey: pkey1_1:pkey2_1
=> (name=103:, value=, timestamp=1409032006570000)
=> (name=103:cvalue:686f676531, value=6675676131, timestamp=1409032006570000)
=> (name=103:value, value=76616c756531315f313033, timestamp=1409049933189000)
=> (name=102:, value=, timestamp=1409032011667000)
=> (name=102:cvalue:686f676531, value=6675676131, timestamp=1409032011667000)
=> (name=102:value, value=76616c756531315f313032, timestamp=1409049943179000)
=> (name=101:, value=, timestamp=1409031979603000)
=> (name=101:cvalue:686f676531, value=6675676131, timestamp=1409031979603000)
=> (name=101:value, value=76616c756531315f313031, timestamp=1409049954219000)
=> (name=100:, value=, timestamp=1409029158989000)
=> (name=100:cvalue:686f6765, value=66756761, timestamp=1409029158989000)
=> (name=100:value, value=76616c756531315f313030, timestamp=1409049974715000)
=> (name=12:, value=, timestamp=1409051010713000)
=> (name=12:cvalue:686f6765, value=66756761, timestamp=1409051010713000)
=> (name=12:value, value=76616c756531315f3132, timestamp=1409051010713000)
-------------------
RowKey: pkey1_2:pkey2_1
=> (name=200:, value=, timestamp=1409029194029000)
=> (name=200:cvalue:686f6765, value=66756761, timestamp=1409029194029000)
=> (name=200:value, value=76616c756532315f323030, timestamp=1409050124020000)
-------------------
RowKey: pkey1_1:pkey2_3
=> (name=102:, value=, timestamp=1409029279630000)
=> (name=102:cvalue:686f676531, value=6675676131, timestamp=1409029279630000)
=> (name=102:value, value=76616c756531335f313032, timestamp=1409050027490000)
-------------------
RowKey: pkey1_1:pkey2_2
=> (name=101:, value=, timestamp=1409029232070000)
=> (name=101:cvalue:686f676531, value=6675676131, timestamp=1409029232070000)
=> (name=101:value, value=76616c756531325f313031, timestamp=1409050045987000)

5 Rows Returned.
Elapsed time: 154 msec(s).

总之(),

    • CQL で複数の Partition Key (上記の例では pkey1, pkey2) を指定すると、PKに指定した 値 が ‘:’ で繋がれて一つの RowKey になる。

 

    • ColumnKey は Partition Key でないカラムキー名を ‘:’ で繋いだものになる (例外として 主キーとして指定されたキーは、値が使用される)

この理由により、CLUSTERING ORDER に指定できるキーが主キーに制限されている

Map のキーは :<キー名> のフォーマットで ColumnKey の一部になる
CQL の CLUSTERING ORDER に指定したキーは、ColumnKey に 値 が入りソートされる (valueに入れてもソートできないため)

値の型がinteger だと、ちゃんと数値の大小でソートされる (キーに入ってるのにどうやって型を識別してるのか不明。素晴らしい)

当在CQL中指定非RowKey的主键(聚簇列:如上例中的skey),则非RowKey的主键的值将被设置为ColumnKey,并与其他键分离。这样,它具有主键的行为。

与 DynamoDB 相比较

DynamoDB的数据结构

DynamoDB

如上所述,DynamoDB的Hash Key就相当于Cassandra的RowKey。这一点完全吻合。
而Range Key则是Cassandra中连接了非RowKey的主键的组合成的。

索引

在Cassandra中,可以创建类似于DynamoDB的“本地辅助索引”(可能)的索引。

什么时候不应该使用索引?

    • カーディナリティが高い (値の種類が多い)データ

 

    • 頻繁に更新されるカラム

 

    大量のカラムがあるpartition中でindexでナロイングする場合

相反地,使用的时机我不太明白。

在Cassandra上的搜索

(Cassandra is a popular open-source distributed database management system.)

可以在SELECT语句的WHERE子句中指定的键

    • Partition Key: 指定する場合、全てのPartition Keyの指定が必須

 

    • Partition Key以外の主キー。数値/日時の比較には大小関係の比較が可能。

 

    Indexを付けたキー (not 主キー)

如果在查询时不指定分区键,查询将跨越多个分区,因此需要添加ALLOW FILTERING选项。
如果添加了此选项,在数据量很大时,查询时间将不确定,因此应尽量避免使用,应该设计能够执行查询而不添加此选项的表结构。