我正在测试Cassandra作为时间序列数据库。
我创建数据模型如下:
CREATE KEYSPACE sm WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 1
};
USE sm;
CREATE TABLE newdata (timestamp timestamp,
deviceid int, tagid int,
decvalue decimal,
alphavalue text,
PRIMARY KEY (deviceid,tagid,timestamp));
在Primary键中,我将deviceid设置为分区键,这意味着具有相同设备ID的所有数据将写入一个节点(它是指一个机器还是一个分区。每个分区最多可以有20亿行)如果我查询同一节点内的数据,检索会很快,我是否正确?我是Cassandra的新手,对分区键和聚类键有点困惑。
我的大部分查询如下:
我将拥有大约2000个deviceid,每个deviceid将有60个tagid / value对。我不确定它是否会包含大量的deviceid,timestamp,tagid / value,tagid / value ....
答案 0 :(得分:10)
我是Cassandra的新手,对分区键和群集键有点困惑。
听起来你理解分区键,所以我只想补充说你的分区键有助于Cassandra找出群集中存储数据的位置(哪个令牌范围)。每个节点负责几个主令牌范围(假设vnode)。将数据写入数据分区时,它将按群集键进行排序。这也是它存储在磁盘上的方式,因此请记住,您的群集键决定了数据在磁盘上的存储顺序。
每个分区最多可以有20亿行
这不完全正确。每个分区最多可支持20亿个单元。单元格本质上是列名/值对。您的群集密钥会自行添加到单个单元格中。因此,通过计算为每个CQL行存储的列值来计算单元格,如果使用群集列,则再添加一个。
根据您的宽行结构,您可能会有远远少于20亿行的限制。此外,这只是存储限制。即使您设法在一个分区中存储了100万个CQL行,查询该分区也会返回如此多的数据,以至于它会笨拙且可能超时。
如果我在同一节点内查询数据,检索会很快,我是否正确?
它至少比击中多个节点的多键查询更快。但是它是否“快速”取决于其他因素,例如行的宽度,以及删除和就地更新等操作的频率。
我的大部分查询如下:
select lastest timestamp of know deviceid and tagid Select decvalue of known deviceid and tagid and timestamp Select alphavalue of known deviceid and tagid and timestamp select * of know deviceid and tagid with time range select * of known deviceid with time range
您当前的数据模型可以支持所有这些查询,最后一个除外。要在timestamp
上执行范围查询,您需要将数据复制到新表中,并构建PRIMARY KEY以支持该查询模式。这称为“基于查询的建模”。我会建立一个这样的查询表:
CREATE TABLE newdata_by_deviceid_and_time (
timestamp timestamp,
deviceid int,
tagid int,
decvalue decimal,
alphavalue text,
PRIMARY KEY (deviceid,timestamp));
该表可以支持timestamp
上的范围查询,同时在deviceid
上进行分区。
但我对这两种模型中看到的最大问题是“无限行增长”。基本上,当您为设备收集越来越多的值时,每个分区将接近20亿个单元格限制(同样,在此之前,事情可能会变慢)。您需要做的是使用称为“时间分组”的建模技术。
对于这个例子,我会说我确定按月划分将使我保持在20亿个单元格限制和允许我需要的日期范围灵活性类型。如果是这样,我会添加一个额外的分区键monthbucket
,我的(新)表将如下所示:
CREATE TABLE newdata_by_deviceid_and_time (
timestamp timestamp,
deviceid int,
tagid int,
decvalue decimal,
alphavalue text,
monthbucket text,
PRIMARY KEY ((deviceid,monthbucket),timestamp));
现在,当我想查询特定设备和日期范围内的数据时,我还会指定monthbucket
:
SELECT * FROM newdata_by_deviceid_and_time
WHERE deviceid='AA23' AND monthbucket='201603'
AND timestamp >= '2016-03-01 00:00:00-0500'
AND timestamp < '2016-03-16 00:00:00-0500';
请记住,monthbucket
只是一个例子。对于您来说,使用季度甚至年份可能更有意义(假设您一年内每deviceid
不存储太多值)。