MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE`之间有啥实际区别?

Posted

技术标签:

【中文标题】MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE`之间有啥实际区别?【英文标题】:What are practical differences between `REPLACE` and `INSERT ... ON DUPLICATE KEY UPDATE` in MySQL?MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE`之间有什么实际区别? 【发布时间】:2012-02-28 10:45:41 【问题描述】:

我需要使用特定键设置记录的所有字段的值(键实际上是复合键),如果还没有具有这样键的记录,则插入记录。

REPLACE 似乎是为了完成这项工作,但同时它的手册页建议 INSERT ... ON DUPLICATE KEY UPDATE.

我应该更好地选择它们中的哪一个?为什么?

我想到的REPLACE 的唯一“副作用”是它会增加自动增量值(幸运的是我没有使用任何值),而INSERT ... ON DUPLICATE KEY UPDATE 可能不会。还有哪些实际差异需要考虑?在哪些特定情况下,REPLACE 可以优于 INSERT ... ON DUPLICATE KEY UPDATE,反之亦然?

【问题讨论】:

INSERT ... ON DUPLICATE KEY UPDATE 实际上也会增加自动增量计数器。不是针对正在更新的记录,而是针对插入的下一条记录。因此,如果最高 ID 为 10,并且您执行重复插入,然后插入新的唯一值,则该行的 ID 将变为 12。 【参考方案1】:

REPLACE 有时似乎是必要的,因为 INSERT IGNORE 似乎不适用于数据转换。

如果我这样做,我只会将最大城市人口设置为自身:

INSERT IGNORE INTO largeCities(stateID、largestCityPop、statePop) SELECT stateID, MAX(city.pop) as largeCityPop, state.pop FROM city 在 city.stateID = state.ID GROUP BY city.stateID ON 上加入状态 重复密钥更新最大城市流行 = 最大城市流行

如果我这样做,我不正确地使用了 GROUP 函数:

INSERT IGNORE INTO largeCities (stateID, maximumCityPop, statePop) SELECT stateID, MAX(city.pop) as largeCityPop, state.pop FROM city 在 city.stateID = state.ID GROUP BY city.stateID ON 上加入状态 重复密钥更新最大城市人口 = MAX(city.pop)

如果我这样做,mysql 将无法识别列名:

INSERT IGNORE INTO largeCities (stateID, maximumCityPop, statePop) SELECT stateID, MAX(city.pop) as largeCityPop, state.pop FROM city 在 city.stateID = state.ID GROUP BY city.stateID ON 上加入状态 重复密钥更新 largeCityPop = city.largestCityPop

这可行,但看起来很丑:

INSERT IGNORE INTO largeCities (stateID, maximumCityPop, statePop) SELECT * FROM (SELECT stateID, MAX(city.pop) as largeCityPop, state.pop FROM city JOIN state on city.stateID = state.ID GROUP BY city.stateID) x ON DUPLICATE KEY UPDATE largeCityPop = 最大的城市流行音乐

【讨论】:

注意:如果外部约束失败INSERT IGNORE 查询将成功完成(并发出警告)!如果你想捕捉这样的错误,最好使用ON DUPLICATE KEY UPDATE而不使用IGNORE【参考方案2】:

“在重复键错误的情况下,存储引擎可能会将 REPLACE 执行为更新而不是删除加插入,但语义是相同的。”

http://dev.mysql.com/doc/refman/5.7/en/replace.html

【讨论】:

【参考方案3】:

在哪些特定情况下,REPLACE 优于 INSERT ... ON 重复密钥更新,反之亦然?

我刚刚发现,对于带有 FEDERATED 存储引擎的表 INSERT...ON DUPLICATE KEY UPDATE 语句被接受但失败(出现错误 1022:无法写入;表中的重复键... ) 如果发生重复键违规 - 请参阅 MySQL 参考手册的this page 上的相应项目符号。

幸运的是,我能够在插入后触发器中使用 REPLACE 而不是 INSERT...ON DUPLICATE KEY UPDATE 来实现将更改复制到 FEDERATED 表的预期结果。

【讨论】:

【参考方案4】:

为了回答性能方面的问题,我用这两种方法做了一个测试

替换成涉及: 1.尝试在桌子上插入 2. 如果 1 失败,删除行并插入新行Insert on Duplicate Key Update 涉及: 1.尝试在表上插入 2.如果1失败,更新行 如果涉及的所有步骤都是插入,那么性能上应该没有差异。速度必须取决于所涉及的更新数量。最坏的情况是所有语句都更新了

我已经在我的 InnoDB 表上尝试了这两个语句,涉及 62,510 个条目(仅更新)。关于露营速度: 替换为:77.411 秒 在重复密钥更新时插入:2.446 秒

Insert on Duplicate Key update is almost 32 times faster.

表大小:Amazon m3.medium 上 1,249,250 行 12 列

【讨论】:

酷统计,你试过Insert on Duplicate Key Replace吗?是不是更慢了? @radtek 你只能写ON DUPLICATE KEY UPDATE,你不能写ON DUPLICATE KEY REPLACE。如果要根据重复键更新现有行的所有值,则必须编写 ON DUPLICATE KEY UPDATE col1=VALUES(col1), col2=VALUES(col2), ... - 您必须手动列出所有列。 我知道我只是在问什么更快,看起来像更新。 REPLACE 命令的目的是什么,如果它是如此无用并且只会引起问题?那这个功能不应该贬值吗?【参考方案5】:

如果您没有列出所有列,我认为REPLACE 将重置所有未提及的列,并在替换的行中使用其默认值。 ON DUPLICATE KEY UPDATE 将保持未提及的列不变。

【讨论】:

【参考方案6】:

当使用REPLACE 而不是INSERT ... ON DUPLICATE KEY UPDATE 时,当多个查询快速到达给定键时,我有时会观察到键锁定或死锁问题。后者的原子性(除了不会导致级联删除)是使用它的更多理由。

【讨论】:

【参考方案7】:

REPLACE 在内部执行删除然后插入。如果您有指向该行的外键约束,这可能会导致问题。在这种情况下,REPLACE 可能会失败或更糟:如果您的外键设置为级联删除,REPLACE 将导致其他表中的行被删除。即使在 REPLACE 操作之前和之后都满足约束条件,也会发生这种情况。

使用INSERT ... ON DUPLICATE KEY UPDATE 可以避免这个问题,因此是首选。

【讨论】:

很好的答案,但在我的实际情况下,这个问题不会被解决。碰撞的可能性虽然可以被认为是 50/50。那我应该怎么选?由于INSERT ... ON DUPLICATE KEY UPDATE 看起来相当“好”,那么在哪些特定情况下,“REPLACE”可能是更好的选择? 我已经进行了相当多的研究,据我所知,没有常见的理由使用 REPLACE 而不是 INSERT ... ON DUPLICATE KEY UPDATE。它本质上是一个遗留功能。除非出于某些特殊原因,您的代码依赖于删除和重新添加的行,以及对索引和自动增量值的相关影响,否则似乎没有任何理由使用它。 On REPLACE 将更新您的 PK 自动增量值,如果它执行 DELETEINSERT。这正是我想要的。我不希望消费者找到同一个PK下的记录,所以他们没有得到任何行。当我希望他们找到它(实际更新)时,我使用UPDATE 所以问题的另一半:你什么时候更喜欢REPLACE而不是INSERT ... ON DUPLICATE KEY UPDATE?为什么INSERT + DELETEUPDATE 更受欢迎?【参考方案8】:

Replace 似乎在 key 已经存在的情况下做了两个操作。也许这意味着两者之间存在速度差异?

(INSERT)一次更新vs一次删除+一次插入(REPLACE)

编辑:我暗示替换可能会更慢实际上是完全错误的。好吧,反正根据这篇博文……http://www.tokutek.com/2010/07/why-insert-on-duplicate-key-update-may-be-slow-by-incurring-disk-seeks/

【讨论】:

以上是关于MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE`之间有啥实际区别?的主要内容,如果未能解决你的问题,请参考以下文章

mysql中的replace into和insert into的效率问题

MySQL中的insert ignore into, replace into等的一些用法小结(转)

MySQL中的insert ignore into, replace into用法总结

MySQL中REPLACE INTO和INSERT INTO的区别分析

MySQL的insert ignore与replace into不同

MySQL中INSERT,UPDATE和REPLACE的区别与用法