Каковы практические различия между `REPLACE` и` INSERT... ON DUPLICATE KEY UPDATE` в MySQL?
Мне нужно установить значения всех полей записи с определенным ключом (на самом деле это композит), вставив запись, если еще нет записи с таким ключом.
REPLACE
, похоже, предназначен для выполнения задания, но в то же время на его странице руководства предлагается
INSERT ... ON DUPLICATE KEY UPDATE
.
Что из них мне лучше выбрать и почему?
Единственный "побочный эффект" REPLACE
, который приходит мне на ум, заключается в том, что он будет увеличивать значения автоинкремента (к счастью, я их не использую), а INSERT ... ON DUPLICATE KEY UPDATE
, вероятно, не будет. Каковы другие практические различия, которые следует учитывать? В каких конкретных случаях REPLACE
может быть предпочтительнее INSERT ... ON DUPLICATE KEY UPDATE
и наоборот?
Ответы
Ответ 1
REPLACE
внутренне выполняет удаление, а затем вставка. Это может вызвать проблемы, если у вас есть ограничение внешнего ключа, указывающее на эту строку. В этой ситуации REPLACE
может потерпеть неудачу или хуже: если ваш внешний ключ установлен на каскадное удаление, REPLACE
приведет к удалению строк из других таблиц. Это может произойти, хотя ограничение было выполнено как до, так и после операции REPLACE
.
Использование INSERT ... ON DUPLICATE KEY UPDATE
позволяет избежать этой проблемы и поэтому предпочтительнее.
Ответ 2
Чтобы ответить на вопрос с точки зрения производительности, я сделал тест, используя оба метода
Заменить Into включает:
1.Попробуйте вставить на стол
2. Если 1 не удается, удалите строку и вставьте новую строку
Вставить в Duplicate Key Update включает:
1.Попробуйте вставить на стол
2. Если 1 не удается, обновите строку
Если все шаги включают в себя вставки, не должно быть разницы в производительности. Скорость должна зависеть от количества используемых обновлений. Худший случай - когда все утверждения обновляются
Я пробовал оба утверждения в моей таблице InnoDB, включающие 62 510 записей (только обновления). На скоростях разбрасывания:
Заменить: 77.411 секунд
Вставка в обновлении повторяющегося ключа: 2.446 секунд
Insert on Duplicate Key update is almost 32 times faster.
Размер таблицы: 1 249 250 строк с 12 столбцами на Amazon m3.medium
Ответ 3
При использовании REPLACE
вместо INSERT ... ON DUPLICATE KEY UPDATE
я иногда наблюдаю проблемы блокировки ключа или тупика, когда несколько запросов поступают быстро для заданного ключа. Атомность последнего (в дополнение к не вызывая каскадных удалений) тем более обоснована для его использования.
Ответ 4
В каких конкретных случаях REPLACE может быть предпочтительнее, чем INSERT... ON DUPLICATE KEY UPDATE и наоборот?
Я только что обнаружил, что в случае таблиц с флагами операторы хранения INSERT...ON DUPLICATE KEY UPDATE
принимаются, но сбой (с ошибкой 1022: невозможно записать; дублировать ключ в таблице...), если происходит нарушение дублирующего ключа - см. соответствующую отметку на этой странице Справочного руководства по MySQL.
К счастью, я смог использовать REPLACE
вместо INSERT...ON DUPLICATE KEY UPDATE
внутри моего триггера insert, чтобы достичь желаемого результата репликации изменений в таблицу FEDERATED.
Ответ 5
Заменить кажется, что он выполняет две операции в том случае, если ключ уже существует. Возможно, это означает, что существует разница в скорости между двумя?
(INSERT) одно обновление по сравнению с одним удалением + одна вставка (ЗАМЕНИТЬ)
ИЗМЕНИТЬ: Мое предположение, что замена может быть медленнее, на самом деле совершенно неверна. Ну, в соответствии с этим сообщением в блоге в любом случае... http://www.tokutek.com/2010/07/why-insert-on-duplicate-key-update-may-be-slow-by-incurring-disk-seeks/
Ответ 6
Если вы не перечислите все столбцы, я думаю, что REPLACE
будет reset любыми не указанными столбцами с их значениями по умолчанию в замененных строках. ON DUPLICATE KEY UPDATE
оставит неизмененные столбцы без изменений.
Ответ 7
"Возможно, что в случае ошибки с дубликатными ключами механизм хранения может выполнять REPLACE как обновление, а не вставку delete plus, но семантика одинакова."
http://dev.mysql.com/doc/refman/5.7/en/replace.html