SELECT col1, col2, COUNT(*)
FROM target_table
GROUP BY col1, col2
HAVING COUNT(*) > 1;
DELETE FROM target_table a
WHERE (col1, col2) IN (
SELECT col1, col2 FROM target_table
GROUP BY col1, col2 HAVING COUNT(*) > 1);
⚠️ 子查詢每次執行皆全表掃描,大數據量極慢。
-- 建立暫存表:每群組保留 MAX(ROWID)(最新寫入)
CREATE TABLE tmp_dup AS
SELECT col1, col2, MAX(rowid) AS keep_rowid
FROM target_table
GROUP BY col1, col2
HAVING COUNT(*) > 1;
-- 刪除非保留行
DELETE FROM target_table a
WHERE a.rowid != (
SELECT b.keep_rowid FROM tmp_dup b
WHERE a.col1 = b.col1 AND a.col2 = b.col2);
COMMIT;
✅ 單次掃描建暫存表,刪除時索引式查找 ROWID,效能提升數量級。
DELETE FROM target_table a
WHERE a.rowid != (
SELECT MAX(b.rowid) FROM target_table b
WHERE a.col1 = b.col1 AND a.col2 = b.col2);
CREATE TABLE tmp_dedup AS SELECT DISTINCT * FROM target_table;
TRUNCATE TABLE target_table; -- 注意:非 DROP,保留結構/權限/索引
INSERT INTO target_table SELECT * FROM tmp_dedup;
DROP TABLE tmp_dedup;
⚠️ 大表建議 INSERT /*+ APPEND */ 直寫 + NOLOGGING 減少 Redo。
INSERT INTO target_table_bak SELECT DISTINCT * FROM target_table;
-- 驗證後 TRUNCATE 原表 → INSERT BACK
DELETE ... WHERE ROWNUM <= 10000 循環,避免 Undo 爆滿與鎖爭用。ALTER SESSION ENABLE PARALLEL DML + DELETE /*+ PARALLEL(t, 8) */ 加速。TRUNCATE 非 DROP,否則需重建索引/權限/約束。