REPLACE INTO 是 MySQL 特有的「插入或替換」語句,簡化了「存在則更新、不存在則插入」(Upsert) 的邏輯。本文詳細說明語法、行為、三種形式、與 INSERT ... ON DUPLICATE KEY UPDATE 的差異、效能考量。
關鍵前提: 表必須有主鍵或唯一索引,否則退化為單純 INSERT,產生重複數據。
-- 1. VALUES 形式 (最常用)
REPLACE INTO tbl_name (col1, col2) VALUES (val1, val2);
-- 2. SELECT 形式
REPLACE INTO tbl_name (col1, col2) SELECT col1, col2 FROM other_table;
-- 3. SET 形式
REPLACE INTO tbl_name SET col1 = val1, col2 = val2;
-- INTO 關鍵字可省略,建議保留以提高可讀性
REPLACE tbl_name (col1, col2) VALUES (val1, val2);
-- 表結構
CREATE TABLE user_login (
user_id BIGINT PRIMARY KEY,
last_login DATETIME NOT NULL,
login_count INT DEFAULT 0
);
-- 邏輯:記錄登入時間,次數 +1
-- REPLACE INTO 寫法 (注意:會重置 login_count 為 0!)
REPLACE INTO user_login (user_id, last_login) VALUES (1001, NOW());
-- 正確寫法:INSERT ... ON DUPLICATE KEY UPDATE
INSERT INTO user_login (user_id, last_login, login_count)
VALUES (1001, NOW(), 1)
ON DUPLICATE KEY UPDATE
last_login = VALUES(last_login),
login_count = login_count + 1;
| 維度 | REPLACE INTO | INSERT ... ON DUPLICATE KEY UPDATE |
|---|---|---|
| 語義 | 刪除舊行 + 插入新行 | 更新現有行 |
| 自增 ID | 重新生成 (舊 ID 丟失) | 保持不變 |
| 未指定欄位 | 重置為預設值 | 保持原值 |
| 外鍵關聯 | 觸發 ON DELETE CASCADE | 不影響關聯行 |
| 觸發器 | 觸發 BEFORE/AFTER DELETE + INSERT | 觸發 BEFORE/AFTER UPDATE |
| 效能 | 較差 (兩次操作) | 較好 (單次操作) |
| 適用場景 | 全行替換、無外鍵、無自增依賴 | 部分欄位更新、保持 ID、有外鍵 |
REPLACE INTO 實際執行 DELETE + INSERT,持有排他鎖 (X Lock)時間較長IODKU 或 LOAD DATA ... REPLACEInnodb_rows_deleted、Innodb_rows_inserted 觀察 REPLACE 實際行為-- PostgreSQL 9.5+
INSERT INTO tbl (id, val) VALUES (1, 'new')
ON CONFLICT (id) DO UPDATE SET val = EXCLUDED.val;
-- SQL Server (MERGE)
MERGE INTO tbl AS target
USING (VALUES (1, 'new')) AS source (id, val)
ON target.id = source.id
WHEN MATCHED THEN UPDATE SET val = source.val
WHEN NOT MATCHED THEN INSERT (id, val) VALUES (source.id, source.val);