MySQL 無 MERGE 語句,但 INSERT ... ON DUPLICATE KEY UPDATE 可實現相同「存在更新、不存在插入」邏輯,且為單條原子 SQL,無競態風險。
INSERT INTO tbl (columnA, columnB, columnC)
VALUES (1, 2, 3)
ON DUPLICATE KEY UPDATE
columnA = IF(columnB > 0, 1, columnA);
INSERT INTO tbl (columnA, columnB, columnC)
VALUES (1, 2, 3)
ON DUPLICATE KEY UPDATE
columnA = IF(columnB > 0, 1, columnA),
columnB = IF(columnC > 0, 1, columnB),
columnC = IF(columnA > 0, 1, columnC);
UPDATE 值與原值相同,InnoDB 不寫入、不產生 Redo、不加鎖,零開銷目標表必須有 PRIMARY KEY 或 UNIQUE INDEX,否則永遠走 INSERT 分支。
| 特性 | Oracle MERGE | MySQL ON DUPLICATE KEY UPDATE |
|---|---|---|
| 語法複雜度 | 較複雜(USING/WHEN MATCHED/NOT MATCHED) | 簡潔(單條 INSERT + UPDATE 子句) |
| 多表關聯 | 支援複雜 JOIN | 單表,需應用層組裝值 |
| 效能 | 優化器深度優化 | 極優(單表、主鍵查找) |
| 可移植性 | Oracle 專有 | MySQL/MariaDB/Percona 通用 |
INSERT INTO user_device (user_id, device_token, last_login, login_count)
VALUES (?, ?, NOW(), 1)
ON DUPLICATE KEY UPDATE
device_token = VALUES(device_token),
last_login = VALUES(last_login),
login_count = login_count + 1;
掌握此模式,單表 Upsert 不再需要應用層 SELECT ... IF EXISTS UPDATE ELSE INSERT 反模式。