我需要检索到期日期为今天的记录。到期日期是使用其他两个字段(startDate
和durationDays
)动态计算的:
SELECT * FROM subscription WHERE startDate + durationDays < currentDate()
为这两列添加两个索引是否有意义?还是应该考虑添加新列expirationDate
并仅为其创建索引?
答案 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中工作,由于尚未发布,您确实不应该使用。
因此,假设您已经在startDate
和durationDays
上创建了二级索引,而只是在查询这些索引时,没有进行任何算术运算。
它执行全表扫描吗?
绝对。
原因是,仅在二级索引列上查询没有分区键。因此,它必须在所有节点上的所有分区上搜索这些值。在大型群集中,您的查询可能会超时。
此外,当找到匹配的数据时,它必须继续查询。由于这些值不是唯一的;完全有可能返回多个结果。卡洛斯(Carlos)100%正确,建议您根据要查询的内容重建表。
建议:
WHERE
子句中使用分区键,以将查询隔离到单个节点。expirationDate
的列,在您的应用中执行日期算术,然后将该值INSERT
插入表中可能更有意义。month
充当“存储桶”(对于您的用例而言,可能会或可能不会)。 PRIMARY KEY ((month),expirationDate,id)
将是一个很好的钥匙。这样,特定月份的所有订阅都存储在一起,由expirationDate
聚集在一起,最后以id
充当唯一性的平局。