刪除重複資料是資料清洗常見需求。針對不同資料量級,本文提供兩種高效方案:中小表用 ROW_NUMBER() 窗口函數、超大分區表用 APPEND + NOLOGGING + EXCHANGE PARTITION。
DELETE FROM prod_grid_inc
WHERE ROWID IN (
SELECT b.row_id2
FROM (
SELECT ROWID AS row_id2,
a.*,
ROW_NUMBER() OVER (PARTITION BY a.prod_id ORDER BY a.insert_date DESC) AS row_num
FROM prod_grid_inc a
) b
WHERE b.row_num >= 2
);
PARTITION BY 定義重複鍵(此處為 prod_id)。ORDER BY 決定保留哪一筆(DESC 保留最新)。ROWID,避免全表掃描 JOIN。原理:以 INSERT /*+ APPEND */ 直寫新分區,再以元資料操作 EXCHANGE PARTITION 秒級切換,避免大量 REDO/UNDO 產生。
APPEND + NOLOGGING 寫入去重後資料。EXCHANGE PARTITION 切換。UNUSABLE)。-- 1. 建立中介表(同分區鍵、同索引)
CREATE TABLE acct_item_mid
PARTITION BY RANGE (acct_date) SUBPARTITION BY HASH (cust_id) SUBPARTITIONS 8
( PARTITION p_201109 VALUES LESS THAN (DATE '2011-10-01') )
AS SELECT * FROM acct_item WHERE 1=0;
-- 2. 寫入去重資料(保留每 cust_id 最大 ROWID)
INSERT /*+ APPEND */ INTO acct_item_mid SUBPARTITION (P_201109_SUB_P_XX)
SELECT * FROM acct_item SUBPARTITION (P_201109_SUB_P_XX) a
WHERE ROWID = (
SELECT MAX(ROWID)
FROM acct_item SUBPARTITION (P_201109_SUB_P_XX) a1
WHERE a.cust_id = a1.cust_id
);
COMMIT;
-- 3. 交換分區(秒級完成)
ALTER TABLE acct_item EXCHANGE SUBPARTITION P_201109_SUB_P_XX
WITH TABLE acct_item_mid
INCLUDING INDEXES
WITHOUT VALIDATION;
-- 4. 重建索引(區域索引)
ALTER INDEX idx_acct_item_cust_id REBUILD SUBPARTITION P_201109_SUB_P_XX;
-- 全域索引需 REBUILD PARTITION 或整體 REBUILD
| 子句 | 作用 |
|---|---|
/*+ APPEND */ | 直寫高水位以上,繞過緩衝區,極大減少 REDO |
NOLOGGING | 操作不產生 REDO(需資料庫非 FORCE LOGGING 模式) |
INCLUDING INDEXES | 同步交換區域索引段 |
WITHOUT VALIDATION | 跳過檢查資料是否符合分區條件,極速完成 |
資料量 < 100 萬筆? → ROW_NUMBER() DELETE
資料量 ≥ 100 萬 且 非分區表? → CTAS 建新表 + RENAME + 索引重建
資料量 ≥ 100 萬 且 分區表? → APPEND + EXCHANGE PARTITION(最快)
ALTER INDEX ... REBUILD。APPEND 會導致表鎖,建議維護窗口執行。FORCE LOGGING 或 Data Guard,NOLOGGING 失效,改用 LOGGING 仍可受益於 APPEND。