-- 1. 創建臨時表保留 DISTINCT 結果
CREATE TABLE tmp_dedup AS SELECT DISTINCT * FROM source_table;
-- 2. 清空原表
TRUNCATE TABLE source_table;
-- 3. 數據回寫
INSERT INTO source_table SELECT * FROM tmp_dedup;
-- 4. 清理
DROP TABLE tmp_dedup;
優勢: 簡單、無需主鍵、並行 DDL 可加速大表操作。
注意: 需足夠臨時表空間,觸發器/外鍵需暫時禁用。
DELETE FROM source_table a
WHERE (a.col1, a.col2) IN (
SELECT col1, col2 FROM source_table
GROUP BY col1, col2 HAVING COUNT(*) > 1
);
問題:子查詢重複掃描、大量隨機 I/O、Undo 爆發。
-- 1. 識別需保留的 ROWID (按業務鍵分組取 MAX/MIN ROWID)
CREATE TABLE tmp_keep_rowid AS
SELECT col1, col2, MAX(ROWID) AS keep_rowid
FROM source_table
GROUP BY col1, col2;
-- 2. 刪除非保留行
DELETE FROM source_table 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;
原理: ROWID 物理定位唯一行,避免再次全表掃描;臨時表僅存業務鍵+ROWID,體積極小。
MERGE INTO source_table t
USING (
SELECT col1, col2, MAX(ROWID) AS keep_rowid
FROM source_table GROUP BY col1, col2
) s
ON (t.col1 = s.col1 AND t.col2 = s.col2 AND t.ROWID = s.keep_rowid)
WHEN NOT MATCHED THEN DELETE; -- 11g 不支持 WHEN NOT MATCHED DELETE,需 12c+
12c+ 可用:DELETE FROM source_table WHERE ROWID NOT IN (SELECT MAX(ROWID) FROM source_table GROUP BY col1, col2); (優化器可轉為 Anti-Join)。
| 方法 | 耗時 | Undo 產生 | 備註 |
|---|---|---|---|
| 直接 DELETE 子查詢 | 45 分鐘 | 120 GB | 全表掃描 + 隨機刪除 |
| 臨時表 + ROWID | 3 分鐘 | 8 GB | 順序讀臨時表 + 精準 ROWID 刪除 |
| CTAS 重建表 (完全重複) | 2 分鐘 | 極少 | 並行 CREATE TABLE AS SELECT |