为什么特定分区上的Cassandra COUNT(*)在相对较小的数据集上花费了很长时间

为什么特定分区上的Cassandra COUNT(*)在相对较小的数据集上花费了很长时间,cassandra,nosql,bigdata,cql,Cassandra,Nosql,Bigdata,Cql,我有一个定义如下的表: 键空间: CREATE TABLE messages.textmessages ( categoryid int, date timestamp, messageid timeuuid, message text, userid int, PRIMARY KEY ((categoryid, date), messageid) ) WITH CLUSTERING ORDER BY (messageid ASC); 使用rep

我有一个定义如下的表:

键空间

CREATE TABLE messages.textmessages (
    categoryid int,
    date timestamp,
    messageid timeuuid,
    message text,
    userid int,
    PRIMARY KEY ((categoryid, date), messageid)
) WITH CLUSTERING ORDER BY (messageid ASC);
使用replication={'class':'SimpleStrategy','replication\u factor':'1}和dustable\u writes=true创建密钥空间消息

表格

CREATE TABLE messages.textmessages (
    categoryid int,
    date timestamp,
    messageid timeuuid,
    message text,
    userid int,
    PRIMARY KEY ((categoryid, date), messageid)
) WITH CLUSTERING ORDER BY (messageid ASC);
目标是拥有宽行时间序列存储,这样
categoryid
date
(一天的开始)就构成了我的分区键,
messageid
提供了集群。这使我能够执行以下查询:

SELECT*FROM messages.textmessages,其中categoryid=2,date='2019-05-14 00:00:00.000+0300',messageId>maxTimeuuid('2019-05-14 00:00:00.000+0300')和messageId

在给定的一天内获取消息;它工作得这么好,这么快

问题

我需要能够通过将上面的
SELECT*
替换为
SELECT count(*)
来计算某一天的邮件数。即使列族中的条目略少于100K,这也需要很长时间;它实际上在
cqlsh
上超时

我已经阅读并理解了很多内容,为什么对于像卡桑德拉(Cassandra)这样的分布式数据库来说,
COUNT
是一项昂贵的操作

问题

为什么即使在以下情况下,此查询也需要如此长的时间:

SELECT COUNT(*) FROM messages.textmessages WHERE categoryid=2 AND date='2019-05-14 00:00:00.000+0300' AND messageId > maxTimeuuid('2019-05-14 00:00:00.000+0300') AND messageId < minTimeuuid('2019-05-15 00:00:00.000+0300')
从messages.textmessages中选择COUNT(*),其中categoryid=2,date='2019-05-14 00:00:00.000+0300',messageId>maxTimeuuid('2019-05-14 00:00.000+0300')和messageId
  • 计数在记录少于100K的特定分区上
  • 在性能卓越的Macbook Pro上,我只有一个Cassandra节点
  • 实例中没有活动的写/读操作;开发笔记本电脑上的分区少于20个

  • 这是可以理解的,因为《卡桑德拉》中“一切都是写的”的概念被忽视了,所以墓碑也会出现

    在分区内或分区之间执行扫描时,我们需要在内存中查看墓碑,以便将它们返回给协调器,协调器将使用它们确保其他副本也知道已删除的行。对于生成大量墓碑的工作负载,这可能会导致性能问题,甚至耗尽服务器堆

    感谢@JimWartnick关于墓碑相关延迟的建议;这是由我插入的
    NULL
    字段生成的大量墓碑造成的。我没有料到这会导致墓碑,也没有料到墓碑会对查询性能造成很大影响;尤其是
    计数

    解决方案

  • 在字段中不存在时使用默认未设置值,或在插入/更新中完全忽略这些值
  • 了解以下事实,如
  • 一个常见的误解是,只有当客户机向Cassandra发出DELETE语句时,墓碑才会出现。一些开发人员认为,选择一种依赖于Cassandra完全没有墓碑的操作方式是安全的。事实上,除了发出DELETE语句之外,还有其他许多事情导致了墓碑。使用TTL插入空值、插入集合和过期数据是常见的逻辑删除源


    数据模型的动机是,给定类别的一天消息存储在一个分区(一个节点?)上;因此,我假设计数操作不应该扫描不同的节点。一定有什么我不明白的,你能粘贴你正在执行的确切查询吗?@AlexOtt我已经用查询明确地更新了问题。谢谢。由于您只有一个节点,分区组件实际上没有帮助/伤害(因为所有数据都在单个节点上)——即使它是必需的。您可能需要了解以下几点:您可能会遇到多少墓碑(您可能需要查看cassandra日志以查看是否看到任何警告)以及sstables的数量/大小。计数必须完成,此时SELECT*只会上升到提取大小,这就是为什么SELECT*可能在计数不起作用的情况下工作。在5秒(本地时间)过去之前,可能有太多的行需要扫描。你可以试试当地的法定人数。你会得到更多time@JimWartnick事实上,我已经解决了这个问题,消除了造成墓碑的原因!我将继续从这个发现中回答我自己的问题。非常感谢,先生。