傳統寫法:宣告游標 → 逐列檢查 → 逐列刪除。百萬筆資料需數小時,且長時間鎖表。
-- 1. 建立同結構暫存表
CREATE TABLE Products_temp (
ProductID INT,
ProductName NVARCHAR(40),
Unit CHAR(2),
UnitPrice MONEY
);
-- 2. 加上唯一索引 + 忽略重複值
-- SSMS:右鍵索引/鍵 → 新增 → 選擇唯一 → 勾選「忽略重複值」
-- T-SQL:
CREATE UNIQUE INDEX UX_Products_temp_Key ON Products_temp (ProductID, ProductName)
WITH (IGNORE_DUP_KEY = ON);
-- 3. 全量複製(重複列自動被忽略)
INSERT INTO Products_temp SELECT * FROM Products;
-- 訊息:'已忽略重複的索引鍵。'
-- 4. 替換原表
DELETE FROM Products;
INSERT INTO Products SELECT * FROM Products_temp;
DROP TABLE Products_temp;
IGNORE_DUP_KEY = ON:插入重複鍵值時,不報錯、不回滾交易,僅忽略該列並發出警告,繼續處理後續列-- 保留每組最早的一筆 (MIN ID)
WITH CTE AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY BizKey ORDER BY ID) AS RN
FROM SourceTable
)
DELETE FROM SourceTable
WHERE ID IN (SELECT ID FROM CTE WHERE RN > 1);
-- 或使用 MERGE (SQL 2008+)
MERGE INTO TargetTable T
USING (SELECT BizKey, MIN(ID) AS KeepID FROM SourceTable GROUP BY BizKey) S
ON T.ID = S.KeepID
WHEN NOT MATCHED BY SOURCE THEN DELETE;
| 方法 | 耗時 | 鎖持有時間 | 日誌量 | 適用場景 |
|---|---|---|---|---|
| 游標逐列刪 | 2-4 小時 | 極長 | 極大 | 極特殊邏輯、無索引權限 |
| 四板斧法 | 10-30 秒 | 極短 | 中等 | 完全重複、有建索引權限 |
| CTE + ROW_NUMBER | 5-15 秒 | 短 | 中等 | 部分欄位去重、保留策略靈活 |
| MERGE | 8-20 秒 | 短 | 中等 | 同步去重、可記錄變更 |
IGNORE_DUP_KEY 僅對 INSERT 生效,UPDATE 仍會報錯