假設有一張鍵值對表 dkv,主鍵為 (k1, k2):
CREATE TABLE `dkv` (
`k1` int(11) NOT NULL DEFAULT '0',
`k2` int(11) NOT NULL DEFAULT '0',
`val` varchar(30) DEFAULT NULL,
PRIMARY KEY (`k1`,`k2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
現有資料如下:
| k1 | k2 | val |
|---|---|---|
| 1 | 1 | value 1-1 |
| 1 | 2 | value 1-1 |
| 1 | 3 | value 1-1 |
| 1 | 5 | value 1-1 |
| 1 | 7 | value 1-1 |
需求:批量寫入多筆資料,若主鍵衝突則更新 val,否則插入新行。若逐筆判斷(SELECT 再 INSERT/UPDATE),100 筆資料就需 200 次 SQL 交互,效率極低。MySQL 提供兩種單語句解決方案。
INSERT DELAYED INTO dkv
VALUES
(1,2,'new 12a'),
(1,3,'new 33ba'),
(1,4,'new 23222'),
(1,6,'new 12333'),
(1,8,'new vaaaa'),
(1,20,'new vaff'),
(1,25,'new vaff')
ON DUPLICATE KEY UPDATE val=VALUES(val);
DELAYED:可選,讓插入延遲執行(MyISAM/MEMORY 引擎支援)。VALUES(val):引用插入列表中對應行的 val 值,實現「衝突時用新值覆蓋」。REPLACE INTO dkv
VALUES
(1,2,'new 12a'),
(1,3,'new 33ba'),
(1,4,'new 23222'),
(1,6,'new 12333'),
(1,8,'new vaaaa'),
(1,20,'new vaff'),
(1,25,'new vaff');
REPLACE 語意為「刪除舊行再插入新行」,主鍵衝突時會先刪除再插入。REPLACE 會導致 ID 變更;ON DUPLICATE KEY UPDATE 則保留原 ID。兩條語句執行後,表資料均變為:
| k1 | k2 | val |
|---|---|---|
| 1 | 1 | value 1-1 |
| 1 | 2 | new 12a |
| 1 | 3 | new 33ba |
| 1 | 4 | new 23222 |
| 1 | 5 | value 1-1 |
| 1 | 6 | new 12333 |
| 1 | 7 | value 1-1 |
| 1 | 8 | new vaaaa |
| 1 | 20 | new vaff |
| 1 | 25 | new vaff |
| 特性 | INSERT ... ON DUPLICATE KEY UPDATE | REPLACE INTO |
|---|---|---|
| 操作本質 | 更新現有行 | 刪除舊行 + 插入新行 |
| 自增 ID | 保持不變 | 重新分配 |
| 外鍵關聯 | 安全 | 可能觸發級聯刪除 |
| 觸發器 | 觸發 UPDATE | 觸發 DELETE + INSERT |
| 效能 | 較優(僅更新) | 稍差(刪除+插入) |
建議:大多數場景優先使用 INSERT ... ON DUPLICATE KEY UPDATE,僅在確確實實需要「完全替換行」時使用 REPLACE。