我正在测试 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));
在主键中,我将deviceid设置为分区键,这意味着如果我查询数据,具有相同设备id的所有数据都将写入一个节点(是指一台机器还是一个分区。每个分区最多可以有20亿行)在同一个节点内,检索会很快,对吗? 我是 Cassandra 新手,对分区键和集群键有点困惑。
我的大部分查询如下:
我将有大约 2000 个 deviceid,每个 deviceid 将有 60 个 tagid/值对。我不确定它是否会是一排宽的 deviceid、时间戳、tagid/值、tagid/值....
我是 Cassandra 新手,对分区键和集群键有点困惑。
听起来您了解分区键,所以我只是补充一下,您的分区键可以帮助 Cassandra 找出集群中存储数据的位置(哪个令牌范围)。 每个节点负责多个主要令牌范围(假设为 vnode)。 当您的数据写入数据分区时,它会按集群键排序。 这也是它在磁盘上的存储方式,因此请记住,您的集群键决定了数据在磁盘上的存储顺序。
每个分区最多可以有 20 亿行
这并不完全正确。 每个分区最多可支持 20 亿个cell。 单元格本质上是一个列名称/值对。 并且您的聚类键本身会添加到一个单元格中。 因此,通过计算为每个 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
执行范围查询,您需要将数据复制到新表中,并构建一个主键来支持该查询模式。 这称为“基于查询的建模”。 我会建立一个这样的查询表:
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
没有存储太多值)。