【问题标题】:Partial Partition Key Querying With Per Partition Limit In Cassandra在 Cassandra 中使用每个分区限制查询部分分区键
【发布时间】:2018-04-06 22:06:56
【问题描述】:

我有一个使用 PRIMARY KEY 设置的表(我们称之为 T),如下所示:

PRIMARY KEY ((A, B), C, ....);

我想像下面这样查询它:

SELECT * FROM T WHERE A = ? and C <= ? PER PARTITION LIMIT 1 ALLOW FILTEIRNG;

(请注意,C 是一个时间戳值。我实际上是在询问第一个分区键属于我输入的所有分区中的最新行)。

这适用于允许过滤命令,我为什么需要它是有道理的;我事先不知道分区键 B,我不在乎 - 我想要所有这些。因此,Cassandra 需要扫描整个分区才能给我结果是有道理的,而且为什么我需要指定它以允许过滤以发生这种情况也是有道理的。

但是,我了解到我们应该不惜一切代价避免“允许过滤”,因为它会对性能产生巨大影响,尤其是在生产环境中。实际上,我只在现有应用程序中非常谨慎地使用 allow 过滤,这通常用于计算此类性质的一次性查询。

我的问题是:有没有办法重组这个表或查询以避免过滤?我认为这是不可能的,因为我事先不知道构成 B 的键,但我想仔细检查以确保。谢谢!

【问题讨论】:

    标签: cassandra


    【解决方案1】:

    如果(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 partition size 密切监视它)。确保始终使用 time_bucket 进行查询,以免它成为范围查询。您要确保最终不会在没有返回结果的情况下经历太多事情(这是允许过滤的危险之一)。

    【讨论】:

    • 我提供的查询格式有效,我自己测试过。您可以执行 A,不指定 B,并限制 C,每个分区限制为 1
    • 具体来说,我想在指定时间之前获取每个唯一元组的最新元组(本例中的分区)。
    • 它确实有效,但它会读取 整个 数据集并忽略不匹配的内容。它的效率非常低,根本不会扩展(允许过滤的风险,这就是为什么它如此强烈地劝阻)。如果想要一个按时间计算的元组...请在上面添加一个新选项。
    • 你是对的,它不能扩展。我使用 20GB 的 cassandra 密钥空间对其进行了测试。我已经为不同的项目设置了类似的时间段,该项目进行分钟、小时、日、月聚合。我想使用这个项目在给定时间提供任意成员数据。您提供的设置在那里完美运行(因为它是我已经做的)。相反,我创建了一个辅助表,其分区键为 (A),其数据是 A 中所有 B 的集合,从时间开始。这个子集比所有 A 和 B 都小很多,所以我可以使用 select * form A where A = A1 and B in (Set)。
    • 你的数据集有多大?
    猜你喜欢
    • 2015-02-01
    • 2019-06-02
    • 2015-06-21
    • 1970-01-01
    • 2017-06-12
    • 2017-04-10
    • 2016-05-11
    • 2016-03-22
    相关资源
    最近更新 更多