首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Oracle 大量資料刪除最佳實務:分批提交避免鎖爭用與 UNDO 爆滿

     編輯:Oracle 資料庫相關知識

問題背景

單次 DELETE 數百萬列會導致:長時間鎖定表、UNDO 表空間暴增、Redo Log 暴增、可能觸發 Snapshot Too Old 錯誤。

解決方案:PL/SQL 分批迴圈刪除

CREATE OR REPLACE PROCEDURE delete_in_batches(
  p_table_name  IN VARCHAR2,
  p_condition   IN VARCHAR2,
  p_batch_size  IN NUMBER DEFAULT 10000
) AS
  v_deleted  NUMBER := 0;
  v_sql      VARCHAR2(4000);
BEGIN
  v_sql := 'DELETE FROM ' || p_table_name || 
           ' WHERE ' || p_condition || 
           ' AND ROWNUM <= :batch_size';

  LOOP
    EXECUTE IMMEDIATE v_sql USING p_batch_size;
    v_deleted := v_deleted + SQL%ROWCOUNT;
    EXIT WHEN SQL%ROWCOUNT = 0;
    COMMIT;  -- 每批提交,釋放鎖與 UNDO
  END LOOP;

  COMMIT;
  DBMS_OUTPUT.PUT_LINE('完成:共刪除 ' || v_deleted || ' 筆資料');
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
    RAISE;
END;
/

呼叫範例

SET TIMING ON
EXEC delete_in_batches('HS_DLF_DOWNLOG_HISTORY', 'NUMDLFLOGGUID < 11100000', 10000);

關鍵優化細節

  • ROWNUM 限制批次大小: 避免單次交易過大
  • 每批 COMMIT: 釋放 Row Lock、UNDO 空間、Redo Log 緩衝
  • 使用動態 SQL: 通用於任意表與條件
  • 自主交易: 若需在主交易外獨立提交,可加 PRAGMA AUTONOMOUS_TRANSACTION;

進階替代方案

效能調校建議

  • 批次大小 5,000~50,000 視表寬度與索引數調整
  • 確認刪除條件欄位有索引,避免 Full Table Scan
  • 監控 V$SESSION_LONGOPS 追蹤進度
  • 離峰時段執行,降低對線上業務影響
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法適用場景優點缺點
Partition Drop/Truncate表已分區,需刪除整個歷史分區秒級完成,不產生 UNDO/Redo需預先規劃分區
CTAS (Create Table As Select)保留資料佔比小(<20%)速度快,可重建索引需鎖表、重建權限/約束/索引
DBMS_REDEFINITION線上重組,零停機不影響線上存取設定複雜,需額外空間