优化在 WHERE 子句中使用算术运算的查询

Optimization of a query which uses arithmetic operations in WHERE clause

我需要检索过期日期为今天的记录。到期日期是使用其他两个字段(startDatedurationDays)动态计算的:

SELECT * FROM subscription WHERE startDate + durationDays < currentDate() 

为这两列加两个索引有意义吗?还是我应该考虑添加一个新列 expirationDate 并仅为它创建一个索引?

Cassandra 和关系数据库之间的主要区别之一是 table 的定义取决于将要使用的查询。数据检索方式 (WHERE statement) 的条件应包含在主键中,因为它的性能优于 table.

上的索引

有多种关于读取路径的资源,以及主键与索引的怪癖,来自 Cassandra 峰会的 talk 可能会有用。

SELECT * FROM subscription WHERE startDate + durationDays < currentDate() 

I'm wondering how does Cassandra handle such a filter as in my example? Does it make a full scan?

首先,您的问题基于 CQL 执行(日期)算术的能力。不能。

> SELECT * FROM subscription WHERE startDate + durationDays < currentDate();
SyntaxException: line 1:43 no viable alternative at input '+' (SELECT * FROM subscription WHERE [startDate] +...)

其次,currentDate() 函数在 Cassandra 3.11.4 中不存在。

> SELECT currentDate() FROM system.local;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Unknown function 'currentdate'"

可以在 Cassandra 4.0 中工作,因为它还没有发布,你真的不应该使用它。

所以让我们假设您已经在 startDatedurationDays 上创建了您的二级索引,并且您只是查询它们,没有任何算术。

它是否执行完整的 table 扫描?

绝对。

原因是,仅在二级索引列上查询没有分区键。因此,它必须在所有节点的所有分区上搜索这些值。在大型集群中,您的查询可能会超时。

另外,当它找到匹配的数据时,它必须继续查询。因为这些值不是唯一的;完全有可能返回多个结果。 100% 正确的 Carlos 建议您根据要查询的内容重建 table。

建议:

  • 尽量不要建有二级索引的table。一如既往
  • 如果您必须使用二级索引构建 table,请尝试在 WHERE 子句中使用分区键以将查询隔离到单个节点。
  • 任何对动态(计算)值的过滤都需要在应用程序端完成。
  • 在您的情况下,创建一个名为 expirationDate 的列可能更有意义,在您的应用程序中计算日期,然后 INSERT 将该值输入您的 table。
  • 您还需要遵循 "time bucket" 模式来处理时间序列数据(看起来就是这样)。假设 month 作为 "bucket" 工作(它可能适合您的用例,也可能不适合您的用例)。 PRIMARY KEY ((month),expirationDate,id) 会是一把好钥匙。这样,特定月份的所有订阅都存储在一起,按 expirationDate 聚类,最后 id 作为唯一性的决胜局。