我需要检索过期日期为今天的记录。使用另外两个字段(startDate
和durationDays
)动态计算到期日期:
SELECT * FROM subscription WHERE startDate + durationDays < currentDate()
为这两列添加两个索引是否有意义?或者我应该考虑添加新列expirationDate
并仅为其创建索引?
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中有效,因为它尚未发布,你真的不应该使用它。
所以我们假设您已经在startDate
和durationDays
上创建了二级索引,而您只是在查询这些索引而没有任何算术。
它是否执行全表扫描?
绝对。
原因是,仅在二级索引列上查询没有分区键。因此,它必须在所有节点上的所有分区上搜索这些值。在大型群集中,您的查询可能会超时。
此外,当它找到匹配的数据时,它必须继续查询。因为这些价值不是唯一的;完全有可能返回几个结果。 Carlos 100%正确建议您根据要查询的内容重建表格。
建议:
WHERE
子句中使用分区键,以将查询隔离到单个节点。expirationDate
的列,在您的应用程序中执行日期算术,然后将INSERT
值放入您的表中可能更有意义。month
是一个“桶”(它可能会或可能不会用于您的用例)。 PRIMARY KEY ((month),expirationDate,id)
将是一个很好的关键。这样,特定月份的所有订阅都存储在一起,由expirationDate
聚集在一起,最后用id
作为唯一性的打破平局。Cassandra和关系数据库之间的主要区别之一是表的定义取决于将要使用的查询。应该如何检索数据的条件(WHERE statement
)应该包含在主键中,因为它将比表上的索引执行得更好。
有关读取路径的多种资源,以及主键与索引的怪癖,来自Cassandra Summit的talk可能很有用。