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

问题描述 投票:1回答:2

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

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

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

cassandra cql
2个回答
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] +...)

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

> 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作为唯一性的打破平局。

1
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.