表 EMPLOYEE (EMP_ID, EMP_NAME, SALARY) 含重複列:
EMP_ID EMP_NAME SALARY 1 sunshine 10000 1 sunshine 10000 ← 重複 2 semon 20000 2 semon 20000 ← 重複 3 xyz 30000 2 semon 20000 ← 重複
CREATE TABLE temp_emp AS SELECT DISTINCT * FROM employee;
TRUNCATE TABLE employee;
INSERT INTO employee SELECT * FROM temp_emp;
DROP TABLE temp_emp;
簡單直觀,但需獨佔表鎖定,大表停機時間長。
Oracle 每列擁有唯一 ROWID(檔案/區塊/列位址),重複資料列 ROWID 必異。保留每組最小 ROWID:
DELETE FROM employee e2
WHERE ROWID NOT IN (
SELECT MIN(ROWID) FROM employee e1
WHERE e1.emp_id = e2.emp_id
AND e1.emp_name = e2.emp_name
AND e1.salary = e2.salary
);
或使用相關子查詢:
DELETE FROM employee e2
WHERE ROWID < (
SELECT MAX(ROWID) FROM employee e1
WHERE e1.emp_id = e2.emp_id
AND e1.emp_name = e2.emp_name
AND e1.salary = e2.salary
);
DELETE FROM employee
WHERE ROWID NOT IN (
SELECT MAX(ROWID) FROM employee
GROUP BY emp_id, emp_name, salary
);
僅掃描一次表即可完成分組與聚合,效能優於方法二。
DELETE FROM employee
WHERE emp_id IN (
SELECT emp_id FROM (
SELECT emp_id,
RANK() OVER (PARTITION BY emp_name, salary ORDER BY emp_id) AS rn
FROM employee
) WHERE rn > 1
);
DELETE FROM employee
WHERE emp_id IN (
SELECT emp_id FROM (
SELECT emp_id,
RANK() OVER (PARTITION BY emp_name, salary ORDER BY emp_id) AS rn
FROM employee
WHERE (emp_name, salary) IN (
SELECT emp_name, salary FROM employee
GROUP BY emp_name, salary HAVING COUNT(*) > 1
)
) WHERE rn > 1
);
測試 500 萬列、4.5 萬重複:
完整掃描版 135 秒 → 過濾版 47 秒(提升 65%)。
ORDER BY rec_date DESC, emp_idHAVING COUNT(*) > 3 搭配 WHERE rn > 3| 方法 | 適用場景 | 效能 | 靈活度 |
|---|---|---|---|
| 暫存表 | 小表、可停機 | 中 | 低 |
| ROWID 子查詢 | 中型表、單一保留規則 | 中 | 低 |
| GROUP BY MAX(ROWID) | 中型表、單一保留規則 | 較好 | 低 |
| RANK() 分析函數 | 大表、複雜保留邏輯 | 最佳(配合過濾) | 極高 |
建議:大數據量優先使用 RANK() 方案並加入重複群組預過濾;無主鍵表可改用全欄位 PARTITION BY。