UPDATE是否成为隐含的​​INSERT

Rae*_*ald 36 cql cassandra

对于Cassandra,如果所选行不存在,那么它是否会UPDATE隐含INSERT?就是说,如果我说

 UPDATE users SET name = "Raedwald" WHERE id = 545127
Run Code Online (Sandbox Code Playgroud)

并且idPRIMARY KEY对的users表,表中有没有行与545127的关键,那将是等同于

 INSERT INTO users (id, name) VALUES (545127, "Raedwald")
Run Code Online (Sandbox Code Playgroud)

我知道相反的情况是正确的:INSERT对于id已经存在的已成为UPDATE行的一部分id.较早的Cassandra文档谈到了插入实际上是"upserts"的原因.

我对CQL3,Cassandra 1.2+版本感兴趣.

Ric*_*ard 41

是的,因为Cassandra UPDATE是同义词INSERT,正如CQL文档中所解释的那样,它说明如下UPDATE:

请注意,与SQL不同,UPDATE不检查行的先前存在:如果之前不存在,则创建行,否则更新.此外,没有必要知道发生了哪些创建或更新.实际上,语义INSERTUPDATE相同.

为了使语义不同,Cassandra需要进行读取才能知道该行是否已存在.Cassandra是写入优化的,因此您可以始终假设它在写入任何写入操作之前不会执行读取操作.唯一的例外是计数器(除非replicate_on_write = false),在这种情况下,增量复制涉及读取.


kbr*_*kbr 24

不幸的是,接受的答案并非 100% 准确。inserts 与updates不同:

cqlsh> create table ks.t (pk int, ck int, v int, primary key (pk, ck));
cqlsh> update ks.t set v = null where pk = 0 and ck = 0;
cqlsh> select * from ks.t where pk = 0 and ck = 0;

 pk | ck | v
----+----+---

(0 rows)
cqlsh> insert into ks.t (pk,ck,v) values (0,0,null);
cqlsh> select * from ks.t where pk = 0 and ck = 0;

 pk | ck | v
----+----+------
  0 |  0 | null

(1 rows)

Run Code Online (Sandbox Code Playgroud)

斯库拉做同样的事情。

在 Scylla 和 Cassandra 中,行是单元格序列。每列都有一个对应的单元格(或者在非冻结集合或 UDT 的情况下是一组单元格)。但是还有一个额外的、不可见的单元格 -行标记(至少在 Scylla 中;我怀疑 Cassandra 有类似的东西)。

行标记对所有其他单元格都已死的行有所不同:当且仅当至少有一个活动单元格时,一行才会显示在查询中。因此,如果行标记处于活动状态,即使所有其他列之前使用例如updates设置为空,该行也会显示出来。

inserts 创建一个实时行标记,而updates 不接触行标记,所以很明显它们是不同的。上面的例子说明了这一点。有人可能会争辩说,行标记是 Cassandra/Scylla 的“内部”,但正如您所见,它们的效果是可见的。无论您喜欢与否,行标记都会影响您的生活,因此记住它们可能会很有用。

遗憾的是没有文档提到行标记(好吧,我发现了这个:https : //docs.scylladb.com/architecture/sstable/sstable2/sstable-data-file/#cql-row-marker但它是在解释的上下文中SSTable 内部结构,它可能更多地致力于 Scylla 开发人员而不是用户)。

奖励:单元格删除

delete v from ks.t where pk = 0 and ck = 0
Run Code Online (Sandbox Code Playgroud)

null更新相同:

update ks.t set v = null where pk = 0 and ck = 0
Run Code Online (Sandbox Code Playgroud)

实际上,单元格删除也不会触及行标记。它只将指定的单元格设置为null.

这与行删除不同:

delete from ks.t where pk = 0 and ck = 0
Run Code Online (Sandbox Code Playgroud)

因为行删除插入行墓碑,这会杀死行中的所有单元格(包括行标记)。您可以说行删除与插入相反。更新和单元格删除介于两者之间。

  • @MattFellows,如果您不删除数据,那没关系。如果您要删除整行(使用“delete from”)(不指定列),那没关系。如果您要删除列(使用“delete X from”,其中“X”是列名),则: 1. 如果您使用 UPDATE,则删除所有列将导致该行消失 2. 如果您使用 INSERT,则删除所有列columns 不会导致行消失 - 它将显示所有常规列等于“null”(它只有主键列),因此这取决于您的用例和期望 (5认同)
  • 这是一个有趣的呼吁。我尝试了你的例子,效果就像你说的那样。当然,当您将值“v”设置为“null”以外的值时,“update”确实会创建一个行标记,因此看起来它对于“null”值的行为有所不同。那一定就是你所说的“一个活细胞”。再说一次,这是一个很好的发现! (3认同)
  • “当然,当您将值 v 设置为 null 以外的值时,`update` 会创建一个行标记”不!尝试将值更新回“null”。编辑,更多详细信息:将“v”“更新”为非“null”,然后将其更新回“null”后,该行将消失。但是,在使用“insert”设置“v”,然后将其更新为“null”后,该行仍将存在。因为“插入”创建了一个行标记。 (2认同)
  • 谢谢。我们将看看博客文章:) (2认同)

Kin*_*tes 15

然而,人们可以做的是:

UPDATE table_name SET field = false WHERE key = 55 IF EXISTS;
Run Code Online (Sandbox Code Playgroud)

这将确保您的更新是真正的更新,而不是upsert.

  • 是的。只是为了澄清:“如果存在”将_防止_“插入” (2认同)