重複數據不僅浪費存儲,還會導致統計信息失真、連接膨脹、報表錯誤。刪除策略需兼顧正確性與性能。
SELECT id_card, COUNT(*)
FROM customer
GROUP BY id_card
HAVING COUNT(*) > 1;
CREATE TABLE tmp_keep_rowid AS
SELECT MAX(rowid) AS keep_rowid, id_card
FROM customer
GROUP BY id_card
HAVING COUNT(*) > 1;
ROWID(物理地址,唯一且隱含插入順序),MAX(rowid) 近似代表「最新插入」。create_time),更準確:SELECT MAX(rowid) KEEP (DENSE_RANK LAST ORDER BY create_time) ...DELETE FROM customer c
WHERE c.rowid NOT IN (SELECT keep_rowid FROM tmp_keep_rowid)
AND c.id_card IN (SELECT id_card FROM tmp_keep_rowid);
/*+ PARALLEL(c, 4) */ 並行加速(Enterprise Edition)。DROP TABLE tmp_keep_rowid;
CREATE TABLE tmp_dedup AS SELECT DISTINCT * FROM source_table;
TRUNCATE TABLE source_table;
INSERT INTO source_table SELECT * FROM tmp_dedup;
DROP TABLE tmp_dedup;
TRUNCATE 瞬間釋放空間、重置 HWM,比 DELETE 快得多且不產生 UNDO/REDO。DELETE FROM source_table a
WHERE a.rowid > (
SELECT MIN(b.rowid)
FROM source_table b
WHERE b.col1 = a.col1
AND b.col2 = a.col2
-- 所有列比較
);
COMMIT,避免 UNDO 爆滿與長鎖定。| 痛點 | 優化手段 |
|---|---|
| 大表自連接/關聯子查詢極慢 | 臨時表預計算 ROWID,轉為簡單 IN/NOT IN 或 EXISTS |
| 全表掃描產生大量 UNDO/REDO | 分批刪除 + COMMIT;或 TRUNCATE + INSERT 重建 |
| 索引維護開銷大 | 刪除前 DISABLE 非主鍵索引,刪除後 REBUILD |
| 並發業務讀寫衝突 | 低峰期操作;或使用 DBMS_REDEFINITION 在線重定義 |
-- 1. 創建中間表(含去重邏輯)
CREATE TABLE customer_interim AS
SELECT * FROM customer WHERE 1=2; -- 結構
ALTER TABLE customer_interim ADD CONSTRAINT pk_cust PRIMARY KEY (id_card);
-- 2. 啟動重定義
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('SCOTT', 'CUSTOMER', 'CUSTOMER_INTERIM');
-- 3. 同步數據(可並行)
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCOTT', 'CUSTOMER', 'CUSTOMER_INTERIM');
-- 4. 完成切換(瞬間鎖表,極短)
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCOTT', 'CUSTOMER', 'CUSTOMER_INTERIM');
適用於 7×24 業務零停機需求,Enterprise Edition 專屬。
ALTER TABLE customer ADD CONSTRAINT uk_id_card UNIQUE (id_card);DISTINCT 或 ROW_NUMBER() OVER (PARTITION BY key ORDER BY load_time DESC) = 1。MERGE / INSERT ... ON CONFLICT(19c+)。刪除重複數據不是一次性動作,而是「識別 → 高效刪除 → 根治預防」的閉環。核心技巧在於:用 ROWID 替代全列比較、用臨時表替代重複計算、用 TRUNCATE/重定義替代大量 DELETE。根據表大小、維護窗口、業務可用性要求選擇最適策略,方能事半功倍。