首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 批次插入遇上唯一索引衝突:IGNORE / REPLACE / ON DUPLICATE KEY UPDATE 三大策略深度對比

     編輯:MySQL 資料庫相關知識

唯一鍵衝突下的批次寫入三板斧:IGNORE vs REPLACE vs ON DUPLICATE KEY UPDATE

批次 INSERT ... SELECT 或應用層批次 INSERT 遇到唯一索引 (主鍵/唯一鍵) 衝突,預設報 1062 錯誤並**整批回滾**。MySQL 提供三種語句級處理策略,行為差異巨大,選型需匹配業務語義。

測試環境建立

CREATE TABLE testtable1 (
  Id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  UserId INT UNIQUE KEY,          -- 唯一業務鍵
  UserName VARCHAR(10),
  UserType INT
) ENGINE=InnoDB;

CREATE TABLE testtable2 LIKE testtable1;

-- testtable1 既有資料
INSERT INTO testtable1 (UserId, UserName, UserType) VALUES
(101, 'aa', 1), (102, 'bbb', 2), (103, 'ccc', 3);

-- testtable2 待導入資料 (含衝突 UserId=101)
INSERT INTO testtable2 (UserId, UserName, UserType) VALUES
(201, 'aaa', 1), (202, 'bbb', 2), (203, 'ccc', 3), (101, 'xxxx', 5);

策略一:INSERT IGNORE — 保留舊值,忽略新值

INSERT IGNORE INTO testtable1 (UserId, UserName, UserType)
SELECT UserId, UserName, UserType FROM testtable2;
  • 行為:逐行檢查唯一鍵衝突,衝突行**靜默丟棄**,不衝突行正常插入。
  • 結果:UserId=101 保留舊值 ('aa', 1);新增 201/202/203。
  • 副作用:自增 ID 會因衝突行預分配而產生**間隙** (1062 錯誤仍消耗自增值)。
  • 適用:冪等導入、日誌去重、不關心衝突行內容。

策略二:REPLACE INTO — 刪除舊行,插入新行 (全欄覆蓋)

REPLACE INTO testtable1 (UserId, UserName)  -- 注意:未指定 UserType
SELECT UserId, UserName FROM testtable2;
  • 行為:衝突時**先 DELETE 舊行,再 INSERT 新行** (隱含事務)。
  • 關鍵陷阱:未在列表中的欄位會被重置為預設值/NULL,而非保留舊值。
    例中 UserType 變為 NULL (或 0,視定義)。
  • 結果:UserId=101 更新為 ('xxxx', NULL);其餘新增。
  • 適用:全欄覆蓋同步、資料以新源為準、表結構簡單 (少欄位)。

策略三:INSERT ... ON DUPLICATE KEY UPDATE — 精準更新指定欄位,保留其餘

-- 僅更新 UserName,保留 UserType
INSERT INTO testtable1 (UserId, UserName, UserType)
SELECT UserId, UserName, UserType FROM testtable2
ON DUPLICATE KEY UPDATE
  UserName = VALUES(UserName);
  -- UserType 不寫 → 保留舊值
  • 行為:衝突時**就地更新**指定欄位,不刪除行,自增 ID 不變,其他欄位保持原值。
  • VALUES(col) 函數引用插入值,等同 testtable2.UserName。
  • 結果:UserId=101 更新 UserName='xxxx',UserType 保留 1;其餘新增。
  • 適用:最通用、最安全:增量同步、計數器累加、部分欄位刷新、审計欄位 (updated_at) 自動維護。

三策略核心差異總結表

進階技巧

  • 計數器原子累加:INSERT INTO stat (day, cnt) VALUES ('2024-01-15', 1) ON DUPLICATE KEY UPDATE cnt = cnt + 1;
  • 多唯一鍵表:ON DUPLICATE KEY UPDATE 觸發任一唯一鍵衝突即更新,需確保業務邏輯無歧義。
  • LAST_INSERT_ID(expr):INSERT ... ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), ... 使衝突時也能獲取該行 ID。
  • 批次效能:單條 SQL 多值 INSERT ... VALUES (),(),() ON DUPLICATE KEY UPDATE ... 比循環執行快數量級。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
維度INSERT IGNOREREPLACE INTOON DUPLICATE KEY UPDATE
衝突行處理丟棄 (保留舊)刪除舊 + 插入新 (全欄覆蓋)就地更新指定欄位 (保留其餘)
未指定欄位無影響重置為 DEFAULT/NULL保留舊值
自增 ID衝突行消耗 ID (產生間隙)衝突行重用舊 ID (DELETE+INSERT)衝突行重用舊 ID (UPDATE)
觸發器INSERT 觸發器 (衝突行不觸發)DELETE + INSERT 觸發器UPDATE 觸發器
外鍵/引用無影響DELETE 可能觸發 CASCADE無 DELETE,安全
效能最快 (無更新開銷)較慢 (DELETE+INSERT)中等 (UPDATE)
推薦場景去重、冪等導入全量覆蓋、結構簡單增量同步、計數器、部分更新