我需要的是使用特定键设置记录的所有字段的值(键实际上是复合键),如果没有带有这样键的记录则插入记录。
REPLACE
似乎意味着要做的工作,但同时它的手册页建议
INSERT ... ON DUPLICATE KEY UPDATE
我应该更好地选择什么?为什么?
我想到REPLACE
的唯一“副作用”是它会增加自动增量值(幸运的是我不使用任何),而INSERT ... ON DUPLICATE KEY UPDATE
可能不会。要记住的其他实际差异是什么?在哪些特定情况下REPLACE
优先于INSERT ... ON DUPLICATE KEY UPDATE
,反之亦然?
答案 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>
答案 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