如果我将日期作为分区键的一部分,那可能不会跨节点传播吗?让日期范围查询变慢?
是的,在两个帐户上都是正确的。这种建模方法称为“时间分桶”,其主要用例是用于随时间增长的时间/事件数据。好消息是,您不需要这样做,除非您的分区预计会变大。根据您当前的预测,每个分区每年写入 253 行,这将是每年 nodetool tablehistograms 计算)。
出于您的目的,我认为按symbol 进行分区并按day 进行集群就足够了。
CREATE TABLE stockquotes (
symbol text,
day date,
price decimal,
PRIMARY KEY(symbol, day))
WITH CLUSTERING ORDER BY (day DESC);
对于大多数基于时间的用例,我们往往更关心最近的数据(您的情况可能是这样,也可能不是)。如果是这样,那么按day 的降序写入数据将提高这些查询的性能。
然后(在写入一些数据之后),这样的日期范围查询将起作用:
SELECT * FROM stockquotes
WHERE symbol='AAPL'
AND day >= '2020-08-01' AND day < '2020-08-08';
symbol | day | price
--------+------------+--------
AAPL | 2020-08-07 | 444.45
AAPL | 2020-08-06 | 455.61
AAPL | 2020-08-05 | 440.25
AAPL | 2020-08-04 | 438.66
AAPL | 2020-08-03 | 435.75
(5 rows)
要验证分区大小可以使用nodetool tablehistograms(一旦数据刷新到磁盘)。
bin/nodetool tablehistograms stackoverflow.stockquotes
stackoverflow/stockquotes histograms
Percentile Read Latency Write Latency SSTables Partition Size Cell Count
(micros) (micros) (bytes)
50% 0.00 0.00 0.00 124 5
75% 0.00 0.00 0.00 124 5
95% 0.00 0.00 0.00 124 5
98% 0.00 0.00 0.00 124 5
99% 0.00 0.00 0.00 124 5
Min 0.00 0.00 0.00 104 5
Max 0.00 0.00 0.00 124 5
每年的分区大小 = 124 字节 x 253 = 31kb
鉴于分区大小很小,该模型可能适用于至少 30 年的数据,然后才会出现任何减速(我建议保持分区 quartercentiry 这样的东西就足够了?无论如何,在短期内,它会没事的。
编辑:
似乎 PK 中使用的任何日期部分都会跨节点传播数据,不是吗?
是的,分区键中使用的日期部分会跨节点传播数据。这实际上就是这样做的目的。您不希望以非绑定行增长的反模式结束,因为分区最终会变得如此之大,以至于它们将无法使用。这个想法是为了确保足够的数据分布。
假设 1/秒,我需要跨年查询,等等。分桶如何工作?
因此,时间分桶的诀窍是在数据分布和查询灵活性之间找到一个“快乐的媒介”。不幸的是,可能会出现查询将访问多个分区(节点)的边缘情况。但我们的想法是建立一个模型来很好地处理其中的大部分问题。
这里的示例问题 1/sec for a year,有点极端。但是解决它的想法是一样的。一天有86400秒。根据行大小,这甚至可能无法按天存储。但是为了争论,说我们可以。如果我们在白天打架,PK 是这样的:
PRIMARY KEY ((symbol,day),timestamp)
WHERE 子句开始看起来像这样:
WHERE symbol='AAPL' AND day IN ('2020-08-06','2020-08-07');
另一方面,几天是可以的,但查询一整年会很麻烦。此外,我们不想构建一个 253 天的 IN 子句。事实上,我不建议人们在 IN 上超过个位数。
这里的一种可能方法是从应用程序触发 253 个异步查询(每天一个),然后在那里组装和排序结果集。在这里使用 Spark(在 RDD 中做所有事情)也是一个不错的选择。实际上,Cassandra 并不是一个出色的报告 API 数据库,因此探索一些其他工具是有价值的。