我有一个表格(让我们称之为T)设置了一个PRIMARY KEY,如下所示:
PRIMARY KEY ((A, B), C, ....);
我想查询它如下:
SELECT * FROM T WHERE A = ? and C <= ? PER PARTITION LIMIT 1 ALLOW FILTEIRNG;
(请注意,C是一个timstamp值。我基本上要求所有分区的最新行,其第一个分区键属于我的输入。)
这适用于allow过滤命令,这就是我需要它的原因;我事先不知道分区键B,我不在乎 - 我想要所有这些。因此,Cassandra需要扫描整个分区才能得到结果,这也是有道理的,为什么我需要指定它以允许对此进行过滤。
但是,我已经读过,我们应该避免“允许过滤”。不惜一切代价,因为它可以产生巨大的性能影响,特别是在生产环境中。实际上,我只在我现有的应用程序中非常谨慎地使用allow过滤,这通常用于计算这种性质的一次性查询。
我的问题是:有没有办法重构这个表或查询以避免过滤?我认为这是不可能的,因为我事先并不知道构成B的键,但我想仔细检查以确定。谢谢!
答案 0 :(得分:2)
如果(A, B)
是您的分区键,则无法有效地进行该查询。您的密钥需要((A), B)
(丢弃群集密钥)。然后是SELECT * FROM T WHERE A = ?
。如果只关心最新的,那么A,B总会被最新的替换。
如果想要从一个时间获得A,B元组,另一个选择是创建一个按时间索引的表,并使元组从那里聚类列,如((time_bucket), A, B, C)
。 time_bucket
是2018-04-06:00:00:00
之类的字符串,其中包含当天的所有事件。然后当您查询时:
> CREATE TABLE example (time_bucket text, A int, B int, C int, D int, PRIMARY KEY ((time_bucket), A, B, C)) WITH CLUSTERING ORDER BY (A ASC, B ASC, C DESC);
> INSERT INTO example (time_bucket, A, B, C, D) VALUES ('2018-04', 1, 1, 100, 999);
> INSERT INTO example (time_bucket, A, B, C, D) VALUES ('2018-04', 1, 1, 120, 999);
> INSERT INTO example (time_bucket, A, B, C, D) VALUES ('2018-04', 1, 1, 130, 999);
> INSERT INTO example (time_bucket, A, B, C, D) VALUES ('2018-04', 1, 2, 130, 999);
> SELECT * FROM example WHERE time_bucket = '2018-04' GROUP BY time_bucket, A, B;
time_bucket | a | b | c | d
-------------+---+---+-----+-----
2018-04 | 1 | 1 | 130 | 999
2018-04 | 1 | 2 | 130 | 999
您将从时间桶分区中的每个行获得第一个结果,其中A和B聚类。如果您使分区足够小(使用更精细的谷物时间桶,如小时或15分钟或某些东西,取决于数据速率)在这里使用ALLOW FILTERING更容易接受,如:
SELECT * FROM example WHERE time_bucket = '2018-04' AND A = 1 AND C < 120 GROUP BY time_bucket, A, B ALLOW FILTERING ;
time_bucket | a | b | c | d
-------------+---+---+-----+-----
2018-04 | 1 | 1 | 100 | 999
因为它全部在一个分区内并且在有限大小内(使用tablestats / max分区大小密切监视它)。确保始终使用time_bucket查询,但它不会成为范围查询。你想确保你不会在没有返回结果的情况下经历太多事情(这是允许过滤的危险之一)。