兩者皆用於「主鍵/唯一鍵衝突時的寫入策略」,但底層行為差異巨大,直接影響資料完整性與自增 ID 增長。本文通過實測案例,揭示核心區別與選型指南。
CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT, b VARCHAR(10), c VARCHAR(10));
INSERT INTO t1 VALUES (1, 'c3', 'c2'), (2, '2', '3');
INSERT INTO t1 (b, c) VALUES ('r2', 'r3'); -- a=3 自增
# 當前資料:a=1,2,3
REPLACE INTO t1 (a, b) VALUES (2, 'a');
# 影響行數:2 (1 刪除 + 1 插入)
結果:a=2 記錄的 c 字段變為 空字串(非 NULL,因無顯式 DEFAULT)。
INSERT INTO t1 (b, c) VALUES ('r4', 'r5');
# 新記錄 a=5(而非預期的 4)
結論:REPLACE 內部執行 DELETE + INSERT,導致自增計數器 +1。
INSERT INTO t1 (a, b) VALUES (3, 'r5') ON DUPLICATE KEY UPDATE b='r5';
# 影響行數:2,c 字段保持原值 'r3'
結果:僅更新指定列 b,保留其他列原值。
INSERT INTO t1 (b, c) VALUES ('r6', 'r7');
# 新記錄 a=7(同樣跳過 6)
結論:ON DUPLICATE KEY UPDATE 同樣導致自增計數器 +1(MySQL 內部機制預分配自增值)。
INSERT INTO t1 (a, b, c) VALUES (33, 'r5', 'c3') ON DUPLICATE KEY UPDATE b='r5';
# 正常插入,所有列生效
| 維度 | REPLACE INTO | INSERT ... ON DUPLICATE KEY UPDATE |
|---|---|---|
| 無衝突時 | 等同 INSERT | 等同 INSERT |
| 有衝突時 | DELETE 舊行 → INSERT 新行(僅保留語句指定列,其餘填默認值) | UPDATE 指定列 → 保留其餘列原值 |
| 自增 ID | +1(因 DELETE+INSERT) | +1(內部預分配機制) |
| 觸發器 | 觸發 BEFORE/AFTER DELETE + INSERT | 觸發 BEFORE/AFTER UPDATE |
| 外鍵約束 | 可能違反(先刪除再插入) | 安全(原地更新) |
| 效能 | 略高(單次寫入) | 略低(讀取舊值、構建新行) |
INSERT ... ON DUPLICATE KEY UPDATE。REPLACE INTO 簡化邏輯、提升寫入效能。個人傾向:優先使用 INSERT ... ON DUPLICATE KEY UPDATE,語義更清晰、資料安全性更高,效能差異在多數場景可忽略。