【问题标题】:Tombstone warning with SELECT LIMIT 1带有 SELECT LIMIT 1 的墓碑警告
【发布时间】:2023-03-10 16:33:01
【问题描述】:
CREATE TABLE test (
    ck INT, 
    pk INT, 
    PRIMARY KEY (ck, pk)
);

for (int i = 1; i < 10000; i++) {
    sessionRW.execute(QueryBuilder.insertInto("test").value("ck", 1).value("pk", i));
}

root@cqlsh:ks> select * from test limit 5;

 ck | pk
----+----
  1 |  1
  1 |  2
  1 |  3
  1 |  4
  1 |  5

(5 rows)


root@cqlsh:ks> delete from test where ck = 1;

root@cqlsh:ks> insert into test(ck,pk) values (1, 0); -- new minimal value
root@cqlsh:ks> select * from test limit 1;

 ck | pk
----+-------
  1 | 0

(1 rows)

WARN  11:37:39 Read 1 live and 9999 tombstoned cells in ks.test (see tombstone_warn_threshold). 1 columns was reque

为什么当我使用“LIMIT 1”执行 SELECT 时会收到墓碑警告?

这些行是按 pk ASC 排序的,该表的较低 pk 值 (0) 是第一行,不会被删除。

我不明白为什么 cassandra 一直在扫描我的表以查找其他结果(因此获取了很多墓碑),因为第一行匹配并且我指定我只想要一行。

如果我没有指定 LIMIT,我可以理解警告。但是当第一行与 LIMIT 1 匹配时,扫描整个表有什么意义呢?

【问题讨论】:

    标签: cassandra


    【解决方案1】:

    因为 cassandra 存储数据的方式。数据作为列存储为单个宽行,即使它通过 cql 看起来像多行。因此,为了到达最后插入的“行”,它还需要读取所有墓碑列。

    下面是插图

        | 1 | 2 | 3 |...|9999| 0 |
    ----+---+---+---+---+----+---+
    ck=1| T | T | T | T |  T |   |
    

    如您所见,它是集群键 1 下的一行。我用“T”标记了墓碑列(或行,如果您愿意)。 Cassandra 读取整行,然后为了找到第一个非墓碑列,它需要循环遍历所有 9999 个墓碑列。

    【讨论】:

    • 但如果插入 (1,1), (1,3), (1,2) 选择将输出 1,2,3 而不是 1,3,2 所以它使用索引而不是插入订单
    • 我必须使用 = 0 才能让 cassandra 使用索引并避免墓碑,如果没有指定,为什么它不能遍历索引
    • 它不会以相同的形状和输出顺序存储数据。而且也没有索引:)
    • 有趣的是,我今天参加了聚会,Jon Haddad 给出了这个例子,说明为什么 cassandra 不是实现队列的好选择
    • 您的解释无效有两个原因:首先插入 0-10000 然后删除 1-10000,按照您的示例,第一列 (0) 不会被删除,但是,它将仍然触发墓碑错误。其次,我确信 Cassandra 以集群键顺序插入列,如果不是这样,处理 where 需要很长时间,并且当你限制 where = 时它仍然会触发墓碑错误。
    【解决方案2】:

    当您执行“select * from test limit 1;”时,Cassandra 必须转到所有节点并过滤整个表以找到第一行。它需要将墓碑流式传输到协调器,因为其他节点可能不同步,并且限制 1 将匹配已删除的行。您应该能够通过指定查询来避免这种情况,以便墓碑无关紧要,例如“select * from test where ck=1 and pk

    【讨论】:

    • 是的,你是对的,我忘了限制分区键ck,但这不是它触发墓碑错误的原因,我是在单节点集群中进行测试。
    【解决方案3】:

    好的,所以我想我找到了答案,答案是 cassandra 在限制 1 之后再进行一次查找(就像你做了限制 2 一样)。

    再插入一行:

    insert into test(ck,pk) values (1, 1);
    

    现在select * from test limit 1; 不会触发墓碑错误。

    但是,如果您执行 LIMIT 2,即使我们有 2 个有效行(在表顺序中的第一个),它也会触发墓碑错误。

    为什么 cassandra 进行 (limit+1) 查找是个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-09
      • 2014-11-06
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多