cassandra UPDATE会变成隐含的INSERT吗

e5nqia27  于 2023-05-22  发布在  Cassandra
关注(0)|答案(4)|浏览(286)

对于Cassandra,如果所选行不存在,UPDATE s是否会成为隐含的INSERT?也就是说,如果我说

UPDATE users SET name = "Raedwald" WHERE id = 545127

idusers表的PRIMARY KEY,并且该表没有键为545127的行,这是否等同于

INSERT INTO users (id, name) VALUES (545127, "Raedwald")

我知道事实恰恰相反:已经存在的idINSERT变成具有该id的行的UPDATE。旧的Cassandra文档提到插入实际上是“upsert”。
我对CQL3,Cassandra版本1.2+的案例感兴趣。

ncgqoxb0

ncgqoxb01#

是的,对于Cassandra,UPDATEINSERT是同义词,正如CQL文档中所解释的那样,它对UPDATE的描述如下:
请注意,与SQL不同,UPDATE不会检查行是否存在:如果之前不存在行,则创建该行,否则更新该行。此外,没有办法知道发生了创建或更新中的哪一个。实际上,INSERTUPDATE的语义是相同的。
为了使语义不同,Cassandra需要执行读取以了解行是否已经存在。Cassandra是写优化的,因此您可以始终假设它在任何写操作中都不会在写之前执行读操作。唯一的例外是计数器(除非replicate_on_write = false),在这种情况下,增量复制涉及读取。

x0fgdtte

x0fgdtte2#

不幸的是,公认的答案并不是100%准确。insert s与update s不同:

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)

Scylla也是一样。
在Scylla和Cassandra中,行是 * 细胞 * 的序列。每一列都有一个对应的单元格(如果是非冻结集合或UDT,则是一组单元格)。但是还有一个额外的、不可见的单元格--* 行标记 *(至少在Scylla中是这样;我怀疑Cassandra有类似的东西)。
行标记会对所有其他单元格都已死亡的行产生影响:当且仅当至少有一个活细胞时,查询中才会显示一行。因此,如果行标记是活动的,则该行将显示,即使所有其他列先前使用例如update s.
insert s创建一个 * 活动行标记 *,而update s不接触行标记,所以很明显它们是不同的。上面的例子说明了这一点。有人可能会说行标记是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

null更新相同:

update ks.t set v = null where pk = 0 and ck = 0

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

delete from ks.t where pk = 0 and ck = 0

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

8dtrkrch

8dtrkrch3#

然而,我们可以做的是:

UPDATE table_name SET field = false WHERE key = 55 IF EXISTS;

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

6ju8rftf

6ju8rftf4#

不,它们不相等,正如@kbr已经解释的那样。您可以在这篇Scylla文档文章中阅读更多关于UPDATEINSERT语句之间的区别-这是开发人员自己最深入的解释。

简而言之,对于表:

CREATE TABLE ks.t (
  pk int, 
  ck int, 
  v int, 
  PRIMARY KEY (pk, ck)
);

声明:

INSERT INTO ks.t (pk, ck, v) VALUES (0, 0, 0);

相当于:

BEGIN UNLOGGED BATCH
    INSERT INTO ks.t (pk, ck) VALUES (0, 0);
    UPDATE ks.t SET v = 0 WHERE pk = 0 AND ck = 0;
APPLY BATCH;

相关问题