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 自动增量值,如果它执行 DELETE
和 INSERT
。这正是我想要的。我不希望消费者找到同一个PK下的记录,所以他们没有得到任何行。当我希望他们找到它(实际更新)时,我使用UPDATE
所以问题的另一半:你什么时候更喜欢REPLACE
而不是INSERT ... ON DUPLICATE KEY UPDATE
?为什么INSERT
+ DELETE
比UPDATE
更受欢迎?【参考方案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的区别分析