如果未在更新中指定 TTL,则 Cassandra TTL 在主键上设置为 0,但如果是,则主键上的 TTL 不会更改

标签 cassandra cql cassandra-2.0 cql3 ttl

Cassandra 中的这种行为似乎违反直觉,我想知道为什么会发生这种情况,并可能解决这个问题。

假设我有一个包含三列的表: pk ,主键,一个 text类型, foo , bigint , 和 bar , 另一个 text .

insert into keyspace.table (pk, foo, bar) values ('first', 1, 'test') using ttl 60;

这会在我的表中创建一行,其生存时间为 60 秒。看着它,它看起来像这样:
  pk  | foo | bar
------------------
first |  1  | test

现在我这样做:
update keyspace.table using ttl 10 set bar='change' where pk='first';

然后,看着这一行,我看到它发生了以下变化:
  pk  | foo | bar
--------------------
first |  1  | change
first |  1  | <<null>>  // after 10 seconds
   << deleted >>        // after the initial 60 seconds

一切都很好。我想要的是bar的生存时间要改变,但没有别的,尤其不是主键。这种行为是意料之中的。

但是,如果我的更新没有 ttl在其中,或者将其设置为 0:
update keyspace.table set bar='change' where pk='first';

然后随着时间的推移,我看到了这种行为。
  pk  | foo | bar
--------------------
first |  1  | change
first |  0  | change   // after the initial 60 seconds

换句话说,该行永远不会被删除。 foo没有被改变,所以它的生存时间仍然有效,并且在它通过后该值被删除(设置为 0)。但是pk它的生存时间确实发生了变化。这完全出乎意料。

为什么只有当我没有在更新中指定生存时间时,主键的生存时间才会改变?我该如何解决这个问题,以便主键的生存时间只有在我明确表示这样做的情况下才会改变?

编辑我还发现,如果我使用的生存时间高于初始生存时间,它似乎也会改变主键的生存时间。
update keyspace.table using ttl 70 set bar='change' where pk='first';

  pk  | foo | bar
--------------------
first |  1  | change
first |  0  | change   // after the initial 60 seconds
   << deleted >>       // after the 70 seconds

最佳答案

您遇到的影响是由 Cassandra 使用的存储模型引起的。

在您的示例中,您有一个没有任何聚类列的表,表中的每一行都映射到数据存储中的一行(通常称为“Thrift 行”,因为这是通过 Thrift API 公开的存储模型)。表中不属于主键的每一列(因此在您的示例中为 foobar 列)都映射到 Thrift 行中的一列。除此之外,在 CQL 行中不可见的额外列被创建为该行存在的标记。

TTL 到期发生在 Thrift 列的级别,而不是 CQL 列。当您INSERT一行,您插入的所有列以及行本身的特殊标记都获得相同的 TTL。

如果您 UPDATE一行,只有您更新的列才会获得新的 TTL。未触及行标记。

使用 SELECT 运行查询时至少有一列 的所有行或 返回存在的特殊行标记。这意味着具有最高 TTL 的列定义了 CQL 行可见的时间,除非行本身的标记(仅在使用 INSERT 语句时才被触摸)具有更长的 TTL。

如果要确保使用与新列值相同的 TTL 更新行的主键,解决方法很简单:使用 INSERT更新行时的语句。这与使用 UPDATE 的效果完全相同。 ,但它也会更新行标记的 TTL。

这种变通方法的唯一缺点是它不能与轻量级事务(IFINSERT 语句中的 UPDATE 子句)结合使用。如果您需要将这些与 TTL 结合使用,则必须使用更复杂的解决方法,但我想这将是一个单独的问题。

如果您想更新某行的某些列,但仍然希望在您插入时指定的 TTL 最初过期后整行消失,这不是 Cassandra 直接支持的。唯一的方法是通过首先查询其中一列的 TTL,然后在 UPDATE 中使用此 TTL 来找出该行剩余的 TTL。手术。例如,您可以使用 SELECT TTL(foo) FROM table1 WHERE pk = 'first'; .但是,这会影响性能,因为它会增加延迟(您必须等待 SELECT 的结果才能运行 UPDATE )。

作为替代方案,您可以添加一个列,该列仅用作“行存在”标记并且仅在 INSERT 期间才触摸。并且永远不会在 UPDATE .然后,您可以简单地忽略此列是 null 的行。 ,但是这种过滤需要在客户端实现,如果您不能在 UPDATE 中指定 TTL,它也无济于事。因为永远不会删除更新的列。

关于如果未在更新中指定 TTL,则 Cassandra TTL 在主键上设置为 0,但如果是,则主键上的 TTL 不会更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27280407/

相关文章:

java - 如何在类路径中修复 "Found Netty' 的 native epoll 传输,但 epoll 不可用。使用 NIO 代替“警告?

Cassandra 非柜台系列

Cassandra 内部批量插入操作

cassandra - 试图登录到 cassandra 的控制台 (cqlsh) 并且它拒绝了我

cassandra-2.0 - DataStax OpsCenter 能否用于监控 Cassandra 社区版集群?

Cassandra Composite Columns - 如何选择 CompositeTypes?

Cassandra:在初始化期间处理提交日志时由于错误而退出

Cassandra where IN 子句限制

cassandra - 是否可以在 Cassandra 中不定义列的情况下插入/写入数据?

python - 如何在 "IN"运算符 Python Cassandra 驱动程序中使用 python 列表?