業務需求:「記錄不存在則插入,存在則更新」(Upsert)。MySQL 提供三種主流寫法,各有優劣。
INSERT INTO clients (client_id, client_name, client_type)
SELECT 10345, 'IBM', 'advertising'
FROM dual
WHERE NOT EXISTS (SELECT 1 FROM clients WHERE client_id = 10345);
NOT EXISTS 檢查,導致重複鍵錯誤或插入兩條。需應用層加鎖或使用 SELECT ... FOR UPDATE 鎖表,效能差。INSERT INTO `table` (a, b, c) VALUES (1, 2, 3)
ON DUPLICATE KEY UPDATE c = c + 1;
INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c = VALUES(a) + VALUES(b);
REPLACE INTO users (id, name, age) VALUES (123, '趙本山', 50);
DELETE + INSERT。遇到唯一鍵衝突先刪除舊行,再插入新行。| 維度 | INSERT ... SELECT | ON DUPLICATE KEY UPDATE | REPLACE |
|---|---|---|---|
| 原子性 | 否(需額外鎖) | 是 | 是 |
| 並發安全 | 差 | 優 | 優 |
| 保留未指定列 | 是 | 是 | 否(重置為默認值) |
| 多唯一鍵行為 | 報錯 | 更新首行 | 刪除所有衝突行 |
| 自增 ID 穩定 | 是 | 是 | 否(重新分配) |
| 觸發器影響 | 單次 | 單次 UPDATE | DELETE + INSERT 觸發兩次 |
VALUES 列表建議 ≤ 1000 行,避免封包過大、鎖持有時間過長。ON DUPLICATE KEY UPDATE 而非 REPLACE。