-- 形式 1:VALUES 列表
REPLACE INTO users (id, name, email, updated_at)
VALUES (1, '張三', 'zhang@example.com', NOW());
-- 形式 2:SELECT 子查詢
REPLACE INTO users (id, name, email, updated_at)
SELECT 1, '張三', 'zhang@example.com', NOW();
-- 形式 3:SET 語法 (MySQL 特有)
REPLACE INTO users SET id=1, name='張三', email='zhang@example.com', updated_at=NOW();
-- ❌ 無主鍵/唯一索引:REPLACE 退化為 INSERT,產生重複數據
CREATE TABLE t1 (id INT, name VARCHAR(20));
REPLACE INTO t1 VALUES (1, 'a'); -- 執行 2 次得到 2 行重複數據
-- ✅ 有主鍵:正常 UPSERT
CREATE TABLE t2 (id INT PRIMARY KEY, name VARCHAR(20));
REPLACE INTO t2 VALUES (1, 'a'); -- 執行 N 次始終 1 行
| 特性 | REPLACE INTO | INSERT ... ON DUPLICATE KEY UPDATE |
|---|---|---|
| 語法簡潔度 | ✅ 簡單 | 較繁瑣 |
| 衝突處理 | DELETE + INSERT | UPDATE (原地修改) |
| 自增列行為 | **重新分配**新自增值 | **保持原值**不變 |
| 觸發器 | 觸發 DELETE + INSERT | 觸發 UPDATE |
| 外鍵級聯 | 觸發 ON DELETE CASCADE | 不觸發刪除級聯 |
| Binlog 記錄 | DELETE + INSERT 兩事件 | 單一 UPDATE 事件 (Row 格式) |
| 部分列更新 | ❌ **不支持** (未指定列置為默認值/NULL) | ✅ **支持** 精確指定更新列 |
| 基於舊值計算 | ❌ 不支持 SET cnt = cnt + 1 | ✅ 支持 SET cnt = cnt + 1 |
| 性能 | 較慢 (雙操作、索引重建) | 較快 (原地更新) |
CREATE TABLE t (id INT PRIMARY KEY, a INT, b INT, c TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
REPLACE INTO t (id, a) VALUES (1, 10); -- b 變為 0 (默認), c 變為當前時間
REPLACE INTO t (id, a) VALUES (1, 20); -- b 再次歸零!數據丟失!
解決:必須指定所有列,或改用 IODKU:
INSERT INTO t (id, a, b, c) VALUES (1, 20, 5, '2023-01-01')
ON DUPLICATE KEY UPDATE a=VALUES(a); -- b, c 保持不變
-- ❌ REPLACE 不支持
REPLACE INTO counters SET id=1, cnt=cnt+1; -- 語法錯誤或邏輯錯誤
-- ✅ IODKU 完美支持
INSERT INTO counters (id, cnt) VALUES (1, 1)
ON DUPLICATE KEY UPDATE cnt = cnt + 1;
INSERT INTO t (id, val) VALUES (1,10),(2,20),(3,30)
ON DUPLICATE KEY UPDATE val = VALUES(val);
ON DELETE CASCADE 外鍵,REPLACE 會連帶刪除關聯表數據!Delete_rows_event + Write_rows_eventREPLACE INTO ...,從庫重放邏輯一致REPLACE INTO 是 MySQL 早期的 UPSERT 實現,**語法簡單但語義危險** (DELETE+INSERT、重置未指定列、不支持增量更新、觸發級聯刪除)。**現代最佳實踐:全面遷移至 INSERT ... ON DUPLICATE KEY UPDATE**,獲得精確控制、更好性能、更安全的複製行為。僅在「確需重置全行、無外鍵、無自增依賴、極簡邏輯」場景下考慮 REPLACE。