MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE'有什么实际区别?

时间:2012-02-06 23:31:25

标签: mysql sql insert replace

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

REPLACE似乎意味着要做的工作,但同时它的手册页建议 INSERT ... ON DUPLICATE KEY UPDATE

我应该更好地选择什么?为什么?

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

8 个答案:

答案 0 :(得分:97)

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

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

答案 1 :(得分:38)

为了回答性能方面的问题,我使用两种方法进行了测试

替换为涉及:
1.试着插在桌子上 2.如果1失败,删除行并插入新行


在重复密钥更新上插入涉及:
1.试着插在桌子上 2.如果1失败,请更新行


如果涉及的所有步骤都是插入,那么性能应该没有区别。速度必须取决于所涉及的更新次数。最糟糕的情况是所有陈述都是更新

我在InnoDB表上尝试了两个语句,涉及62,510个条目(仅限更新)。在坎帕速度上:
替换为:77.411秒
在重复密钥更新时插入:2.446秒

Insert on Duplicate Key update is almost 32 times faster.

表格大小:亚马逊m3.medium上有12列的1,249,250行

答案 2 :(得分:7)

使用REPLACE代替INSERT ... ON DUPLICATE KEY UPDATE时,有时会在多个查询快速到达给定密钥时发现密钥锁定或死锁问题。后者的原子性(除了不会导致级联删除)更有理由使用它。

答案 3 :(得分:2)

  

在什么特殊情况下,REPLACE比INSERT ... ON更受欢迎   DUPLICATE KEY UPDATE,反之亦然?

我刚刚发现了一种困难的方法,即在具有FEDERATED存储引擎的表INSERT...ON DUPLICATE KEY UPDATE语句被接受但是失败的情况下(错误1022:无法写入;表中的重复键)。 ..)如果发生重复键违规 - 请参阅MySQL参考手册的this page上的相应项目符号。

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

答案 4 :(得分:1)

替换似乎在密钥已存在的情况下执行了两次操作。也许这意味着两者之间存在速度差异?

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

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

答案 5 :(得分:1)

如果您没有列出所有列,我认为REPLACE将重置任何未提及的列及其替换行中的默认值。 ON DUPLICATE KEY UPDATE将保留未提及的列。

答案 6 :(得分:1)

&#34;在重复键错误的情况下,存储引擎可能会将REPLACE作为更新而不是删除加插入来执行,但语义是相同的。&#34; < / p>

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

答案 7 :(得分:0)

有时似乎需要替换,因为INSERT IGNORE似乎不适用于数据转换。

如果这样做,我只会为其设置“ largestCityPop”:

  

在IGNORE中插入最大的城市(stateID,largestCityPop,statePop)   选择stateID,MAX(city.pop)作为最大的CityPop,state.pop从城市   在city.stateID = state.ID上加入状态   重复键更新maximumCityPop = maximumCityPop

如果执行此操作,则可能会错误地使用GROUP函数:

  

在IGNORE中插入最大的城市(stateID,largestCityPop,statePop)   选择stateID,MAX(city.pop)作为最大的CityPop,state.pop从城市   在city.stateID = state.ID上加入状态   重复键更新maximumCityPop = MAX(city.pop)

如果执行此操作,MySQL将无法识别列名:

  

在IGNORE中插入最大的城市(stateID,largestCityPop,statePop)   选择stateID,MAX(city.pop)作为最大的CityPop,state.pop从城市   在city.stateID = state.ID上加入状态   重复键更新maximumCityPop = city.largestCityPop

这有效,但看起来很丑陋:

  

在IGNORE中插入最大的城市(stateID,largestCityPop,statePop)   SELECT * FROM(SELECT stateID,MAX(city.pop)as maximumCityPop,   state.pop来自city.stateID = state.ID GROUP BY上的城市加入状态   city.stateID)x在重复密钥更新上maximumCityPop =   maximumCityPop