UPDATE 是否成为隐含的 INSERT

Does an UPDATE become an implied INSERT

提问人:Raedwald 提问时间:6/28/2013 更新时间:5/18/2023 访问量:36962

问:

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

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

并且是表的,并且该表没有键为 545127 的行,这是否等价于idPRIMARY KEYusers

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

我知道情况恰恰相反:已经存在的 for an 变成了与 that 的行的 an .出于这个原因,较早的 Cassandra 文档谈到插入实际上是“更新插入”。INSERTidUPDATEid

我对 CQL3、Cassandra 版本 1.2+ 的案例很感兴趣。

卡桑德拉 CQL

评论


答:

57赞 Richard 6/28/2013 #1

是的,因为 Cassandra 是 的同义词,正如 CQL 文档中所解释的那样,它说了以下内容:UPDATEINSERTUPDATE

请注意,与 SQL 不同,它不检查行的先前存在:如果之前不存在,则创建该行,否则进行更新。此外,没有办法知道发生了哪些创建或更新。事实上,和 的语义是相同的。UPDATEINSERTUPDATE

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

评论

0赞 محمد 1/30/2018
嗨,我有一个问题,更新键与插入相同,但是如果我想更新另一列上的数据(例如用户名或...和 insert 一样吗?合并批量数据的最佳解决方案是什么?
22赞 KingOfHypocrites 6/28/2015 #2

然而,人们可以做的是:

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

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

评论

2赞 WestCoastProjects 7/22/2019
是的。澄清一下:将阻止if existsinsert
0赞 efex09 10/15/2020
需要启用 LightWeightTransactions 才能支持此类查询。
37赞 kbr 2/5/2020 #3

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

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 有类似的东西)。

行标记对所有其他单元格都已死的行有影响:当且仅当至少有一个活动单元格时,查询中才会显示一行。因此,如果行标记处于活动状态,则该行将显示,即使所有其他列之前都使用例如 s 设置为 null。update

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

遗憾的是,没有文档提到行标记(好吧,我找到了这个: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

这与行删除不同:

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

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

评论

3赞 Aaron 2/5/2020
这是一个有趣的呼吁。我尝试了你的例子,它就像你说的那样有效。当然,当您将值设置为 以外的值时,确实会创建一个行标记,因此它看起来对值的行为有所不同。那一定是你提到的“一个活着的细胞”。同样,这是一个很好的发现!vnullupdatenull
2赞 kbr 2/5/2020
“当然,当您将值 v 设置为 null 以外的值时,确实会创建一个行标记”不!尝试将值更新回 。编辑,更多细节:在'ing到non-,然后更新回,该行将消失。但是,在使用 ,然后将其更新为 后,该行将仍然存在。因为创建了一个行标记。updatenullupdatevnullnullvinsertnullinsert
1赞 kbr 2/5/2020
更新为 non- 后看到该行的原因是该单元格处于活动状态。行标记不是。在 non- 之后,有两个活的单元格:单元格和行标记。vnullvinsertnullvv
2赞 kbr 2/6/2020
谢谢。我们将看到有关博客文章:)
4赞 kbr 2/15/2021
@MattFellows,如果您不删除数据,也没关系。如果要删除整行(使用 )(不指定列),则无关紧要。如果要删除列(使用 ,其中列名是列名),则: 1. 如果您使用了 UPDATE,则删除所有列将导致该行消失 2.如果您使用了 INSERT,则删除所有列不会导致该行消失 - 它将在所有常规列等于的情况下出现(它只有主键列),因此这取决于您的用例和期望delete fromdelete X fromXnull
0赞 winwin 5/18/2023 #4

不,正如@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;