無主鍵/唯一約束的表易產生全列重複行。以 EMPLOYEE(EMP_ID, EMP_NAME, SALARY) 為例,檢測重複:
-- 方式 1:GROUP HAVING
SELECT EMP_ID, EMP_NAME, SALARY, COUNT(*)
FROM EMPLOYEE
GROUP BY EMP_ID, EMP_NAME, SALARY
HAVING COUNT(*) > 1;
-- 方式 2:ROWID 關聯
SELECT * FROM EMPLOYEE E1
WHERE ROWID NOT IN (
SELECT MAX(ROWID) FROM EMPLOYEE E2
WHERE E1.EMP_ID = E2.EMP_ID
AND E1.EMP_NAME = E2.EMP_NAME
AND E1.SALARY = E2.SALARY
);
CREATE TABLE TEMP_EMP AS SELECT DISTINCT * FROM EMPLOYEE;
TRUNCATE TABLE EMPLOYEE;
INSERT INTO EMPLOYEE SELECT * FROM TEMP_EMP;
DROP TABLE TEMP_EMP;
-- 保留最大 ROWID
DELETE FROM EMPLOYEE E2
WHERE ROWID NOT IN (
SELECT MAX(E1.ROWID) FROM EMPLOYEE E1
WHERE E1.EMP_ID = E2.EMP_ID
AND E1.EMP_NAME = E2.EMP_NAME
AND E1.SALARY = E2.SALARY
);
-- 或保留最小 ROWID
DELETE FROM EMPLOYEE E2
WHERE ROWID < (
SELECT MAX(E1.ROWID) FROM EMPLOYEE E1
WHERE E1.EMP_ID = E2.EMP_ID
AND E1.EMP_NAME = E2.EMP_NAME
AND E1.SALARY = E2.SALARY
);
/*+ HASH_AJ */ 提示DELETE FROM EMPLOYEE
WHERE ROWID NOT IN (
SELECT MAX(ROWID) FROM EMPLOYEE
GROUP BY EMP_ID, EMP_NAME, SALARY
);
ALTER SESSION ENABLE PARALLEL DMLDELETE FROM EMPLOYEE
WHERE ROWID IN (
SELECT ROWID FROM (
SELECT ROWID,
ROW_NUMBER() OVER (PARTITION BY EMP_ID, EMP_NAME, SALARY ORDER BY ROWID) RN
FROM EMPLOYEE
) WHERE RN > 1
);
DELETE ... WHERE ROWID IN (SELECT ...) 直接引用CREATE OR REPLACE PROCEDURE PURGE_DUP_BATCH(
P_TABLE VARCHAR2,
P_COLS VARCHAR2, -- 去重列列表,逗號分隔
P_BATCH NUMBER DEFAULT 50000
) AS
V_SQL VARCHAR2(32767);
V_CNT NUMBER;
BEGIN
LOOP
V_SQL := 'DELETE FROM ' || P_TABLE ||
' WHERE ROWID IN (' ||
' SELECT RID FROM (' ||
' SELECT ROWID RID, ROW_NUMBER() OVER (PARTITION BY ' || P_COLS || ' ORDER BY ROWID) RN' ||
' FROM ' || P_TABLE ||
' ) WHERE RN > 1 AND ROWNUM <= ' || P_BATCH ||
')';
EXECUTE IMMEDIATE V_SQL;
V_CNT := SQL%ROWCOUNT;
COMMIT;
EXIT WHEN V_CNT = 0;
DBMS_LOCK.SLEEP(1); -- 緩釋鎖競爭
END LOOP;
END;
/
-- 調用
EXEC PURGE_DUP_BATCH('EMPLOYEE','EMP_ID,EMP_NAME,SALARY',20000);
ALTER TABLE EMPLOYEE ADD CONSTRAINT PK_EMP PRIMARY KEY (EMP_ID)DISTINCT/ROW_NUMBER 清洗MERGE INTO ... USING ... ON (PK) WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ...| 表大小 | 維護窗口 | 外鍵/觸發器 | 推薦方案 |
|---|---|---|---|
| < 10萬行 | 任意 | 少/無 | 臨時表重建 |
| 10萬-1000萬 | 有 | 有 | GROUP BY ROWID / ROW_NUMBER |
| > 1000萬 | 短/無 | 複雜 | 分批 ROW_NUMBER + 並行 DML |
| 極大 (億級) | 無窗口 | 複雜 | CTAS 新分區表交換 / GoldenGate 異構同步 |