表 T 中 (col1, col2) 為業務唯一鍵,需刪除重複組合,保留任一筆。
DELETE FROM t a
WHERE (col1, col2) IN (
SELECT col1, col2 FROM t
GROUP BY col1, col2 HAVING COUNT(*) > 1
);
CREATE TABLE tmp_dup AS
SELECT col1, col2 FROM t
GROUP BY col1, col2 HAVING COUNT(*) > 1;
CREATE INDEX idx_tmp_dup ON tmp_dup(col1, col2);
DELETE FROM t a
WHERE (col1, col2) IN (SELECT col1, col2 FROM tmp_dup);
臨時表大幅縮小 IN 子查詢結果集,配合索引可從小時級降至秒級。
利用 Oracle 隱藏 ROWID(每列唯一物理地址),保留 ROWID 最大(最新插入)者:
DELETE FROM t a
WHERE a.ROWID > (
SELECT MIN(b.ROWID) FROM t b
WHERE a.col1 = b.col1 AND a.col2 = b.col2
);
MIN(ROWID) 代表最早插入的那筆,刪除其餘。若要保留最新,改用 MAX(ROWID) 並刪除 ROWID < MAX(...)。
若有 create_time 或 update_time,可直接用時間判斷:
DELETE FROM t a
WHERE a.create_time < (
SELECT MAX(b.create_time) FROM t b
WHERE a.col1 = b.col1 AND a.col2 = b.col2
);
若時間相同再以 ROWID 斷捨。
DELETE ... WHERE ROWNUM <= 10000 迴圈,避免 UNDO 爆滿、鎖升級。CREATE TABLE t_new AS
SELECT * FROM t
WHERE ROWID IN (
SELECT MAX(ROWID) FROM t GROUP BY col1, col2
);
DROP TABLE t;
RENAME t_new TO t;
-- 重建索引、約束、授權
TRUNCATE PARTITION 清除歷史重複區段。SELECT col1, col2, COUNT(*) FROM t GROUP BY col1, col2 HAVING COUNT(*) > 1;
結果為 0 行表示清理完成。