如何获取Cassandra表中的行数

66

这是一个非常基础的问题,但它实际上已经困扰我好几天了。在Cassandra中是否有一种好的方法获得给定表的COUNT(*)等价物呢?

我将把数亿行数据移动到 C* 中进行一些负载测试,并且在将大量数据通过网络传输之前,我希望至少可以在一些样本ETL作业中获取行计数。

我最好的想法是使用Python循环遍历每一行并自动递增计数器。还有更好的确定(甚至估计)C*表行大小的方法吗?我也尝试在 Datastax Ops Center 中查找是否可以确定行大小,但如果可以的话,我不知道如何做到。

还有其他人需要在C*中获取表的count(*)吗?如果是,你是如何处理的?


1
请参考以下链接获取有关Cassandra列族行数的信息:https://dev59.com/F3I-5IYBdhLWcg3wPF12 - Amit G
11个回答

73

是的,你可以使用COUNT(*)。这里是文档

使用COUNT(*)的SELECT表达式返回与查询匹配的行数。或者,您可以使用COUNT(1)获得相同的结果。

计算users表中的行数:

SELECT COUNT(*) FROM users;

81
轮到你了。我们都会轮流扮演白痴的角色。我的轮到明天了,迫不及待地等着呢。 - Don Branson
5
目前我的基准是使用5个带有SSD和32GB内存的节点群集。对于一百万行数据,需要大约一分半钟才能返回计数结果*。我还有很多调整和微调要做。但就目前而言,“开箱即用”,速度确实有点慢。 - Evan Volgas
4
这似乎指向了后关系时代的口号 - 设计你的查询。创建一个保持计数器的表格,每当你添加一行时都会增加计数。然后查询将很快返回。我预计它的响应时间在几毫秒的数量级上。 - Don Branson
4
如果我需要频繁地对我的表执行count(*)操作,我肯定会同意你的观点。这只是用于检查和控制总数,“我发送了一百万条记录......它们都到达了吗?”这种情况。 - Evan Volgas
4
一般来说,在Cassandra中运行聚合查询虽然在技术上是支持的,但这并不是一个好的实践。此外,如果你最终有数百万行数据,这个查询很可能会超时。使用下面列出的一些nodetool命令通常是更好的方法。 - ammills01
显示剩余2条评论

23

为避免Cassandra上count(*)通常发生的超时,您可以使用复制操作。

cqlsh -e "copy keyspace.table_name (first_partition_key_name) to '/dev/null'" | sed -n 5p | sed 's/ .*//'


很好!这很有帮助。 - user1401472
4
@shubham,你能否解释一下这段代码吗?它在做什么?有没有任何副作用? - Anurag Rana

18

nodetool tablestats非常方便,可快速获得行估计值(和其他表统计信息)。

对于特定的表,可以使用nodetool tablestats <keyspace.table>


1
我没有看到使用tablestats的估计计数,COPY似乎是一个不错的选择,但对于更大的表(磁盘上剩余的可用存储空间较少),管理空间有点困难。还有其他方法吗? - Anil Kapoor
我原本认为“键的数量”足够了,但现在我看到它是指分区键。如果您知道列大小,可以尝试使用Memtable单元格计数。https://docs.datastax.com/en/archived/cassandra/3.0/cassandra/tools/toolsTablestats.html - Lucian Thorr
1
我在nodetool tablestats下看不到行估计。 - IceTea

13
您可以使用 dsbulk count 来检索表的总计数。我曾经在使用上述命令时遇到读取超时的问题,最终通过以下命令成功地获取了计数:
例如, dsbulk count -k <keyspace_name> -t <table_name> 有关dsbulk的更多信息,请访问此处

太棒了!这个提示非常有用! - chris.w.mclean

10

如果你不需要精确计数,你可以通过nodetool cfhistograms获得一些估算值(这些值是估计值)。

如果你运行的是DSE,你也可以使用Spark。


你如何使用Spark来加速计数?例如,我有大约十亿条记录,我正在使用Spark来计算行数。这需要1小时30分钟才能完成。以下是更多详细信息: http://stackoverflow.com/questions/40778936/apache-spark-sql-is-taking-forever-to-count-billion-rows-from-cassandra/40781384?noredirect=1#comment68807487_40781384 - user1870400
现在没有 cfhistograms 选项,而 tablehistograms 在行数方面似乎没有提供太多有用的信息。 - Alexis Wilke
cfhistograms和tablehistograms是同一件事,就像我说的那样,你可以得到一些大致的估计,而不是严格的计数。 - phact

5
$nodetool settimeout read 360000
cqlsh -e "SELECT COUNT(*) FROM table;" --request-timeout=3600

10
虽然这段代码可能回答了问题,但提供有关它是如何解决问题的以及为什么能够解决问题的上下文信息会提高答案的长期价值。 - Tiago Martins Peres

4
我是一名有用的助手,可以为您翻译文本。

我一直在使用Elasticsearch,这可能是解决这个问题的答案...假设您愿意使用Elassandra而不是Cassandra。

搜索系统维护许多统计数据,并且在最后更新后几秒钟内,它应该对您在表中有多少行有一个很好的了解。

这里是一个匹配所有查询请求,可以为您提供信息:

curl -XGET \
     -H 'Content-Type: application/json' \
     "http://127.0.0.1:9200/<search-keyspace>/_search/?pretty=true" \
     -d '{ "size": 1, "query": { "match_all": {} } }'

其中<search-keyspace>是Elassandra创建的keyspace。通常会被命名为<keyspace>_<table>,所以如果你有一个名为foo的keyspace和一个名为bar的表在该keyspace中,则URL将使用.../foo_bar/...。如果您想获取所有表中行的总数,则只需使用/_search/
输出是一个JSON,看起来像这样:
{
  "took" : 124,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 519659,                <-- this is your number
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "foo_bar",
        "_type" : "content",
        "_id" : "cda683e5-d5c7-4769-8e2c-d0a30eca1284",
        "_score" : 1.0,
        "_source" : {
          "date" : "2018-12-29T00:06:27.710Z",
          "key" : "cda683e5-d5c7-4769-8e2c-d0a30eca1284"
        }
      }
    ]
  }
}

在速度方面,这个过程只需要毫秒级的时间,无论行数多少。我有许多百万行的表格,它的运行非常顺畅。不需要等待几个小时或者类似的事情。
正如其他人所提到的,Elassandra仍然是由许多计算机并行使用的系统。如果您经常进行许多更新,计数器将很快改变。因此,只有当您防止进一步更新足够长的时间以使计数器稳定时,从Elasticsearch获得的数字才是正确的。否则,它总是会是一个近似值。

3

对于大表的 count(*),您可以在 Cassandra 上使用 Presto。我已经测试过了,效果很好。

请参考以下链接: 关键词搜索:Cassandra question v3.11.3...

select count(*) from table1

网址:Cassandra问题v3.11.3 ... select count(*) from table1


1
如果您使用C# Linq组件适配器,则可以使用以下内容:
var t = new Table<T>(session);
var count = t.Count().Execute();

1
Java驱动程序的等效物是什么?你知道吗? - Manu Chadha

-2

考虑使用带有列约束条件的ALLOW FILTERING,然后对值进行求和。

例如:

SELECT count(*)
FROM my_table
WHERE datetime_id >= '2020-09-16' ALLOW FILTERING;

SELECT count(*)
FROM my_table
WHERE datetime_id < '2020-09-16' ALLOW FILTERING;

4
请不要这样做 - 这样会导致你的集群崩溃或超时。 - Alex Ott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接