首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle SQL 執行驟慢根因分析:TRUNCATE 導致統計資訊失效、索引失效與重建統計資訊標準化修復流程

     編輯:Oracle 資料庫基礎

故障現場還原

  • 表 `T_BIG` 日增 300 萬行,歷史積累 2 億+ 行。
  • 優化策略:每日 `TRUNCATE TABLE T_BIG` → 當日數據入庫 → 執行 `UPDATE` 統計匯總。
  • **故障**:`TRUNCATE` 後首日 `UPDATE` 耗時 **數小時** (預期秒級);手工 `REBUILD INDEX` + `ANALYZE` 後恢復 **6 秒**;第三天故障復發。

根因深度剖析

  1. TRUNCATE 重置 HWM 但不重置索引統計:索引結構保留,但 **統計資訊 (NUM_ROWS, LEAF_BLOCKS, DISTINCT_KEYS 等) 仍反映截斷前的 2 億行狀態**。
  2. CBO 依據過期統計產生錯誤計畫:以為表仍有 2 億行,選擇 **全表掃描** 或 **錯誤連接順序/方法**,導致 `UPDATE` 走全表掃描、索引未被使用。
  3. 動態採樣不足:預設 `OPTIMIZER_DYNAMIC_SAMPLING=2`,對大表採樣不夠精準,無法糾正統計謊言。
  4. 為何第三天復發?** 統計資訊收集後隨業務寫入逐漸偏離,若無定時收集機制,再次陷入「統計謊言」陷阱。

標準化修復流程 (生產級 SOP)

-- 每日批次腳本 (TRUNCATE 後、載入前/後執行)
TRUNCATE TABLE t_big;                           -- 1. 清空表、重置 HWM
-- 可選:DROP INDEX ... / 但 11g+ 索引可保留,僅標記 UNUSABLE 再 REBUILD 更快
-- DROP INDEX idx_t_big_1; DROP INDEX idx_t_big_2; ...

-- 2. 載入當日數據 (INSERT /*+ APPEND */ 或 SQL*Loader/Data Pump)
INSERT /*+ APPEND */ INTO t_big SELECT ... FROM stage_table;
COMMIT;

-- 3. 重建索引 (若已 DROP) 或 REBUILD (若標記 UNUSABLE)
ALTER INDEX idx_t_big_1 REBUILD;
ALTER INDEX idx_t_big_2 REBUILD;
-- 並行重建大幅縮短時間
-- ALTER INDEX idx_t_big_1 REBUILD PARALLEL 4;

-- 4. **關鍵:收集統計資訊** (CASCADE=>TRUE 同步收集索引統計)
EXEC DBMS_STATS.GATHER_TABLE_STATS(
  ownname          => 'SCHEMA',
  tabname          => 'T_BIG',
  cascade          => TRUE,          -- 同步索引統計
  method_opt       => 'FOR ALL COLUMNS SIZE AUTO',  -- 直方圖自動
  estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,  -- 11g+ 自動採樣
  degree           => 4              -- 並行收集
);

-- 5. 驗證執行計畫
EXPLAIN PLAN FOR UPDATE ...;  -- 確認走索引、成本合理

自動化避坑:建立統計資訊收集調度作業

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_GATHER_T_BIG_STATS',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN DBMS_STATS.GATHER_TABLE_STATS(''SCHEMA'',''T_BIG'',CASCADE=>TRUE,METHOD_OPT=>''FOR ALL COLUMNS SIZE AUTO'',DEGREE=>4); END;',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY; BYHOUR=3; BYMINUTE=0',  -- 凌晨 3 點
    enabled         => TRUE,
    comments        => 'T_BIG 每日載入後統計收集,防止計畫劣化'
  );
END;
/
-- 並開啟自動統計收集 (11g+ 預設開啟)
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTOSTATS_TARGET','AUTO');

進階:TRUNCATE 後索引處理選型

策略操作優點缺點建議場景
保留索引 + REBUILD`ALTER INDEX ... REBUILD`不需 DROP/CREATE 權限、保留授權/同義詞索引段空間不釋放 (若表大幅縮小)表大小波動不大、權限受限
DROP + CREATE`DROP INDEX ...; CREATE INDEX ...`徹底釋放空間、可調整索引定義需 DDL 權限、同義詞/授權需重建表大幅縮小、結構調整
標記 UNUSABLE + REBUILD`ALTER INDEX ... UNUSABLE; ... REBUILD`載入數據時跳過索引維護 (快)、載入後並行重建載入期間查詢不可用該索引**大量載入首選** (配合 `SKIP_UNUSABLE_INDEXES=TRUE`)

結語

**TRUNCATE 重置數據但不重置統計**,導致 CBO 「以訛傳訛」產生劣質計畫。**「載入 → 重建索引 → 收集統計 (CASCADE=TRUE)」三部曲是大表日刷新的鐵律**。配合 `DBMS_SCHEDULER` 固化為自動化作業,並啟用 `AUTO_SAMPLE_SIZE` + 並行收集,將「統計資訊失效導致 SQL 慢」風險納入常態化管控。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved