針對不同場景需採用不同策略,本文提供高效能、可保留最新資料的標準解法。
-- 查詢重複的業務鍵組合
SELECT COL1, COL2, COUNT(*)
FROM TABLE_NAME
GROUP BY COL1, COL2
HAVING COUNT(*) > 1;
-- 直接刪除:效能極差,可能鎖死資料庫
DELETE FROM TABLE_NAME A
WHERE (COL1, COL2) IN (
SELECT COL1, COL2 FROM TABLE_NAME
GROUP BY COL1, COL2 HAVING COUNT(*) > 1
);
-- 建立臨時表儲存重複鍵
CREATE GLOBAL TEMPORARY TABLE TMP_DUP_KEYS ON COMMIT PRESERVE ROWS
AS SELECT COL1, COL2 FROM TABLE_NAME
GROUP BY COL1, COL2 HAVING COUNT(*) > 1;
-- 刪除重複 (仍會刪除該鍵下所有列,含最新)
DELETE FROM TABLE_NAME A
WHERE (A.COL1, A.COL2) IN (SELECT COL1, COL2 FROM TMP_DUP_KEYS);
Oracle 每列隱含 ROWID,物理位置編碼,越新產生的 ROWID 越大 (近似)。
-- 單一 SQL 完成:刪除重複鍵下非最大 ROWID 的列
DELETE FROM TABLE_NAME A
WHERE A.ROWID != (
SELECT MAX(B.ROWID)
FROM TABLE_NAME B
WHERE A.COL1 = B.COL1 AND A.COL2 = B.COL2
);
-- 1. 建立臨時表:每個業務鍵保留的目標 ROWID
CREATE GLOBAL TEMPORARY TABLE TMP_KEEP_ROWID ON COMMIT PRESERVE ROWS
AS
SELECT COL1, COL2, MAX(ROWID) AS KEEP_ROWID
FROM TABLE_NAME
GROUP BY COL1, COL2;
-- 2. 刪除非保留列
DELETE FROM TABLE_NAME A
WHERE A.ROWID != (
SELECT B.KEEP_ROWID
FROM TMP_KEEP_ROWID B
WHERE A.COL1 = B.COL1 AND A.COL2 = B.COL2
);
-- 3. 提交並清理
COMMIT;
DROP TABLE TMP_KEEP_ROWID;
-- 1. 建立去重後的臨時表
CREATE TABLE TABLE_NAME_DEDUP AS
SELECT DISTINCT * FROM TABLE_NAME;
-- 2. 刪除原表 (或 RENAME)
DROP TABLE TABLE_NAME;
-- 3. 將去重資料寫回 (可選:重建索引、約束、授權)
-- 這裡假設同名重建
CREATE TABLE TABLE_NAME AS SELECT * FROM TABLE_NAME_DEDUP;
-- 4. 清理
DROP TABLE TABLE_NAME_DEDUP;
-- 前置:建立同結構備份表
CREATE TABLE TABLE_NAME_BAK AS SELECT * FROM TABLE_NAME WHERE 1=0;
-- 去重插入
INSERT INTO TABLE_NAME_BAK SELECT DISTINCT * FROM TABLE_NAME;
-- 切換 (需停機維護窗口)
-- RENAME TABLE_NAME TO TABLE_NAME_OLD;
-- RENAME TABLE_NAME_BAK TO TABLE_NAME;
-- 重建索引、約束、授權、同義詞
-- 利用 ROWID 刪除完全重複中較舊的列
DELETE FROM TABLE_NAME A
WHERE A.ROWID > (
SELECT MIN(B.ROWID)
FROM TABLE_NAME B
WHERE A.COL1 = B.COL1
AND A.COL2 = B.COL2
-- 這裡需列出所有欄位比較,或用 ROWID 直接比較
AND A.ROWID != B.ROWID
);
-- 注意:完全重複時 ROWID 比較需謹慎,建議用方法 1/2
| 場景 | 資料量 | 推薦方案 | 預估耗時 (千萬列) |
|---|---|---|---|
| 部分欄位重複,保留最新 | < 10 萬 | 單一 SQL (ROWID != MAX) | < 1 分鐘 |
| 部分欄位重複,保留最新 | 10 萬 - 1 億 | 臨時表預計算 MAX ROWID | 5-30 分鐘 |
| 部分欄位重複,保留最新 | > 1 億 | 分批處理 + 臨時表 + 平行 DML | 視批次而定 |
| 完全重複列 | 所有 | CREATE TABLE AS SELECT DISTINCT + 重建 | 全表掃描時間 × 2 |