50

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

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

并且id是表PRIMARY KEYusers,并且该表没有键为 545127 的行,这是否相当于

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

我知道情况正好相反:一个已经存在的INSERTfor an变成了带有 that 的行的一个。由于这个原因,较早的 Cassandra 文档谈到插入实际上是“upserts”。idUPDATEid

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

4

3 回答 3

50

是的,因为 CassandraUPDATE是 的同义词INSERT,正如CQL 文档中解释的那样,它对以下内容进行了说明UPDATE

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

为了使语义不同,Cassandra 需要进行读取以了解该行是否已经存在。Cassandra 是写优化的,所以你总是可以假设它在任何写操作上都不会先读再写。唯一的例外是计数器(除非replicate_on_write = false),在这种情况下,增量复制涉及读取。

于 2013-06-27T16:41:54.563 回答
27

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

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 和 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

null更新相同:

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

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

这与行删除不同:

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

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

于 2020-02-05T12:07:40.863 回答
20

然而,可以做的是:

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

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

于 2015-06-28T15:29:37.640 回答