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

时间:2019-04-25 20:33:01

标签: cassandra cql

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

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

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

我想知道Cassandra如何处理示例中的过滤器?它会进行全面扫描吗?

首先,您的问题取决于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上创建了二级索引,而只是在查询这些索引时,没有进行任何算术运算。

它执行全表扫描吗?

绝对。

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

此外,当找到匹配的数据时,它必须继续查询。由于这些值不是唯一的;完全有可能返回多个结果。卡洛斯(Carlos)100%正确,建议您根据要查询的内容重建表。

建议:

  • 尽量不要用二级索引建立表。像以往一样。
  • 如果必须使用辅助索引来构建表,请尝试在WHERE子句中使用分区键,以将查询隔离到单个节点。
  • 对动态(计算)值进行任何过滤都需要在应用程序端进行。
  • 对于您来说,创建一个名为expirationDate的列,在您的应用中执行日期算术,然后将该值INSERT插入表中可能更有意义。
  • 您还需要遵循“时间段”模式来处理时间序列数据(这看起来是这样)。假设month充当“存储桶”(对于您的用例而言,可能会或可能不会)。 PRIMARY KEY ((month),expirationDate,id)将是一个很好的钥匙。这样,特定月份的所有订阅都存储在一起,由expirationDate聚集在一起,最后以id充当唯一性的平局。