为啥 UPSERT 执行 DELETE 和 INSERT 而不是 UPDATE (SQLite)

Posted

技术标签:

【中文标题】为啥 UPSERT 执行 DELETE 和 INSERT 而不是 UPDATE (SQLite)【英文标题】:Why does UPSERT does a DELETE and INSERT instead of UPDATE (SQLite)为什么 UPSERT 执行 DELETE 和 INSERT 而不是 UPDATE (SQLite) 【发布时间】:2015-03-23 16:12:32 【问题描述】:

我想知道为什么至少在使用 Peewee 时,当条目已经在表中时,UPSERT 会执行 DELETE 和 INSERT 而不是 UPDATE?

有什么理由比“删除然后插入”而不是“尝试更新,否则插入”更可取?

UPDATE 是否比 DELETE & INSERT 更耗时?还是 UPSERT 真的是一个 INSERT(force=True) 查询?

【问题讨论】:

我不认为 SQLite 支持 UPSERT.. 没有关于它的文档:sqlite.org/docs.html 我的错。显然该层是由 Peewee 处理的。 Juste编辑了这个问题。但是,从我读过的内容来看,这似乎是一个常见的实现。 可能是更新中的数据占用空间较大,无法就地更新。 @BeNdErR,SQLite 通过INSERT OR REPLACE INTO 支持UPSERT。 @bsuire,peewee 不会“伪造”一个 upsert。如果数据库支持,则会发出原生 upsert,否则会收到错误消息。 【参考方案1】:

我想知道为什么至少在使用 Peewee 时,当条目已经在表中时,UPSERT 会执行 DELETE 和 INSERT 而不是 UPDATE?

Peewee 没有明确地先删除然后插入。如果您使用的是 SQLite,它确实支持 upsert,那么 peewee 将发出:

INSERT OR REPLACE INTO <table> ...

这就是 peewee 实现 upsert 的方式。 Peewee 本身不会发出单独的 DELETE 语句。

见https://www.sqlite.org/lang_replace.html

【讨论】:

【参考方案2】:

这不是更好吗:

UPDATE t SET a = 'pdf' WHERE id = 2;
INSERT INTO t(id, a) SELECT 2, 'pdf' WHERE changes() = 0;

如果更新失败,则更改()=0,因此它会进行插入。

【讨论】:

以上是关于为啥 UPSERT 执行 DELETE 和 INSERT 而不是 UPDATE (SQLite)的主要内容,如果未能解决你的问题,请参考以下文章

为啥 mgo 不返回插入文档的 ID?

为啥work bench 执行不了mysql delete语句

C语言中已经有了malloc和free,为啥还需要new和delete?

c++(在类中)执行buf=new char[i];delete []buf; 为啥没有调用构造和析构函数?

为啥“SELECT 1 from <table>”会导致另一个进程上的 LCK_M_IX 执行 DELETE

列索引超出范围:1,列数:0