我们目前正在测试Cassanda作为大量关于通信事件的元数据的数据库。由于大多数查询仅限于单个客户,因此按客户ID分类是有意义的。但是,这意味着分区会随着时间的推移而无限增长。我正在努力想出一个看起来足够干净的解决方案。
第一个想法是使用客户ID和一些时间间隔的复合密钥。还有其他选择,可能更好,有机增长吗?
由于我们希望尽可能少的分区读取,我想只需使用年份来为每个客户的每个分区设置数据的上限。但是,如果我没有误会,这会相当不均匀地分配数据。这可以通过移动几个月甚至几周/几天来解决吗?
我确信这是一个经常出现的问题,我有兴趣听取人们提出的各种解决方案。
编辑:为了使查询类型更加清晰,他们将根据每个客户的大时间片计算聚合。理想情况下,我们只有这个:
PRIMARY KEY((customer_id),时间戳)
但是,正如我所提到的,这将导致多年来每个分区的未绑定增长。
答案 0 :(得分:3)
分区可以容纳大量的行,但是如果多年来你的卷都是一个问题,你可以从哈希表中借用一个想法。当多个值散列为某个值时,额外值将存储为溢出链接列表。
我们可以将相同的想法扩展到分区。当高容量客户的分区“填满”时,我们会在列表中添加额外的分区。
所以你可以像这样定义你的表:
CREATE TABLE events (
cust_id int,
bucket int,
ts int,
overflow list<int> static,
PRIMARY KEY ((cust_id, bucket), ts));
对于大多数客户,您只需将存储桶设置为零并使用单个分区即可。但是如果零分区太大,则在静态列表中添加1以指示您现在还将数据存储在存储桶1中。然后,您可以根据需要向列表中添加更多分区。
例如:
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 0, 1);
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 0, 2);
SELECT * from events;
cust_id | bucket | ts | overflow
---------+--------+----+----------
123 | 0 | 1 | null
123 | 0 | 2 | null
现在假设你想开始为这个客户使用第二个分区,只需将它添加到静态列表中:
UPDATE events SET overflow = overflow + [1] WHERE cust_id=123 and bucket=0;
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 1, 3);
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 1, 4);
因此要检查客户是否正在使用任何溢出桶分区:
SELECT overflow FROM events WHERE cust_id=123 and bucket=0 limit 1;
overflow
----------
[1]
现在,您可以对分区进行范围查询:
SELECT * FROM events WHERE cust_id=123 and bucket IN(0,1) AND ts>1 and ts<4;
cust_id | bucket | ts | overflow
---------+--------+----+----------
123 | 0 | 2 | [1]
123 | 1 | 3 | null
您可以定义“桶”以包含您想要的任何含义,例如年份或某物。请注意,溢出列表定义为静态,因此它只对每个分区存储一次而不是每个事件行。
可能更常规的方法是按cust_id和year进行分区,但是你需要以某种方式知道开始和结束年份才能进行查询。使用溢出方法,第一个存储桶是主存储器,并且具有标准的已知值,如0,用于读取。但缺点是您需要读取以了解要写入哪个存储桶,但如果每个客户在通信会话期间生成大量事件,那么可能的开销不会太大。