MySQL中的“ REPLACE”和“ INSERT…ON DUPLICATE KEY UPDATE”之间有什么实际区别?


79

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

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。– marlar

Answers:


113

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

使用INSERT ... ON DUPLICATE KEY UPDATE避免了这个问题,因此是优选的。


1
好的答案,但是在我的实际情况下,这个问题将无法解决。但是可以将碰撞的机会视为50/50。那我该怎么选择呢?并且INSERT ... ON DUPLICATE KEY UPDATE看起来“更好”的情况下,那么在哪些特定情况下“ REPLACE”会是更好的选择?
伊万

3
我已经做了相当多的研究,据我所知,没有普遍的理由使用REPLACE而不是INSERT ...在重复键更新上。从本质上讲,这是一项旧功能。除非出于某些特殊原因,您的代码依赖于要删除和重新添加的行以及对索引和自动递增值的相关影响,否则似乎没有任何理由使用它。
弥敦道(Nathan Stretch)

2
REPLACE如果执行DELETE和,则打开将更新您的PK自动增量值INSERT。这正是我想要的。我不希望消费者在相同的PK下查找记录,因此他们不会获得任何行。当我希望他们找到它(实际更新)时,我使用UPDATE
radtek

所以,问题的另一半:当你更喜欢REPLACEINSERT ... ON DUPLICATE KEY UPDATE?为什么INSERT+会比+更DELETE受青睐UPDATE
LemonPi '18

58

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

替换为:1.
尝试在表
2上插入。如果1失败,则删除行并插入新行

重复键更新上的插入涉及:1.
尝试在表
2上插入。如果1失败,则更新行

如果涉及到所有步骤,插入时,性能应该没有差异。速度必须取决于所涉及的更新数量。最糟糕的情况是所有语句都更新时

我已经在InnoDB表上尝试了这两个语句,其中涉及62,510个条目(仅更新)。使用Camping速度时:
替换为: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

9

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


3

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


3

在哪些特定情况下,替换(REPLACE)优先于插入(INSERT)...在重复密钥更新时优先,反之亦然?

我刚刚发现很难采用带有FEDERATED存储引擎INSERT...ON DUPLICATE KEY UPDATE语句的表的方式,但是如果有重复键,则会失败(错误1022:无法写入;表中有重复键...)发生违规-请参阅《 MySQL参考手册》此页上的相应要点。

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




0

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

如果执行此操作,则仅将maximumCityPop设置为其自身:

插入IGNORE到maximumCities(stateID,largestCityPop,statePop)中选择stateID,MAX(city.pop)作为maximumCityPop,state.pop从城市JOIN上city.stateID = state.ID GROUP BY city.stateID进行重复密钥更新maximumCityPop = maximumCityPop

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

将IGNORE插入到maximumCities(stateID,largestCityPop,statePop)中选择stateID,MAX(city.pop)作为maximumCityPop,state.pop从城市JOIN上city.stateID = state.ID GROUP BY city.stateID进行重复密钥更新maximumCityPop = MAX (city.pop)

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

插入IGNORE到maximumCities(stateID,largestCityPop,statePop)中选择stateID,MAX(city.pop)作为maximumCityPop,state.pop。 .largestCityPop

这可行,但是看起来很丑陋:

INSERT IGNORE INTO到largestCities(stateID,largestCityPop,statePop)SELECT * FROM(选择stateID,MAX(city.pop)作为bigestCityPop,state.pop重复键更新maximumCityPop = maximumCityPop

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.