SQL предоставляет различные способы обновления или вставки данных в таблицу:
Когда и что использовать:
INSERT.UPDATE с условиями.MERGE или UPSERT — это экономит сложность и уменьшает количество SQL-запросов.Пример (PostgreSQL):
INSERT INTO employees(id, name, salary) VALUES (1, 'Ivan', 100000) ON CONFLICT (id) DO UPDATE SET salary = EXCLUDED.salary;
Влияние на производительность и целостность:
Что произойдет, если попытаться выполнить UPSERT на уникальном поле, но в одной и той же транзакции одновременно вставить и обновить одну и ту же строку?
Правильный ответ: Возможно возникновение ошибки блокировки/конфликта, т.к. транзакция попытается изменить одну и ту же строку дважды. Операция не завершится или завершится ошибкой deadlock в зависимости от СУБД.
Пример:
BEGIN; INSERT INTO users(id, name) VALUES (1, 'Oleg') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name; UPDATE users SET name = 'Petr' WHERE id = 1; COMMIT;
При неправильном порядке и уровне изоляции возможен конфликт изменений.
История №1
В одной логике миграции данных использовали комбинацию SELECT, а затем INSERT или UPDATE, что иногда приводило к тому, что другая транзакция устанавливала данные раньше, и происходила ошибка «duplicate key». Это вызвало частые сбои ночного экспорта данных, потребовалось заменить логику на UPSERT.
История №2
В проекте на MySQL некорректно применяли ON DUPLICATE KEY UPDATE, который некорректно учитывал составные уникальные ключи. В результате часть данных не обновлялась, а появлялись дубликаты. Проблему удалось выявить только на боевом стенде.
История №3
В проекте использовали UPDATE вместо UPSERT для синхронизации данных пользователя. При сбоях соединения происходила потеря части данных, поскольку обновление пропускалось для новых пользователей. После анализа полностью внедрили MERGE/UPSERT.