資深 DBA 面對「Oracle 很慢」時,不會急著抓最慢 SQL,而是遵循:網路 → 硬體 → OS → Oracle 參數 → 資料結構 → 單支 SQL 的層層排查。網路與硬體往往難以變更,應用程式碼也難動,因此Oracle 參數調校與資料結構優化是最高 CP 值的切入點。本文總結三大核心調優動作(三板斧),針對 OLTP、CBO 環境極具實效。
SGA 太小導致頻繁磁碟 I/O,太大造成 OS 交換。依實體記憶體建議配置:
| 實體記憶體 | SGA 總量 | Shared Pool | Database Buffer Cache | 備註 |
|---|---|---|---|---|
| 512 MB | ~240 MB | 60~80 MB | 120~150 MB | 小型應用,8i 用 DB_BLOCK_BUFFERS |
| 1 GB | ~500 MB | 100~150 MB | 300~400 MB | 9i+ 用 DB_CACHE_SIZE 直接設定 |
| 2 GB | ~1.2 GB | 300~500 MB | 剩餘 | Shared Pool 超過 500 MB 邊際效益遞減 |
| >2 GB (32-bit) | ≤1.75 GB | 300~500 MB | 盡可能大 | 32-bit 限制 1.75 GB,需 OS 支援突破 |
| >2 GB (64-bit) | 50%~70% | 300~500 MB | 剩餘 | 64-bit 無上限,預留 30% 給 OS 與 PGA |
-- 檢查 SGA 元件大小
SELECT * FROM V$SGAINFO;
-- Buffer Cache 命中率
SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME IN ('db block gets','consistent gets','physical reads');
-- 命中率 = 1 - (physical reads / (db block gets + consistent gets))
Oracle 預設優化模式 CHOOSE:若表無統計資訊 → RBO(規則基礎)→ 全表掃描;有統計 → CBO(成本基礎)→ 走索引。未分析的表是全表掃描元兇。
-- 單表完整分析(<100 萬筆建議)
ANALYZE TABLE TABLE_NAME COMPUTE STATISTICS;
-- 大表抽樣分析(百分比勿太低,建議 10%~30%)
ANALYZE TABLE BIG_TABLE ESTIMATE STATISTICS SAMPLE 20 PERCENT;
-- 索引分析
ANALYZE INDEX IDX_NAME COMPUTE STATISTICS;
-- 10g/11g+ 建議用 DBMS_STATS(功能更強、支援並行、直方圖)
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'TABLE_NAME', CASCADE => TRUE, DEGREE => 4);
-- 檢查最後分析時間
SELECT TABLE_NAME, LAST_ANALYZED FROM DBA_TABLES WHERE OWNER = 'SCHEMA';
SELECT INDEX_NAME, LAST_ANALYZED FROM DBA_INDEXES WHERE TABLE_OWNER = 'SCHEMA';
-- 開啟 AUTOTRACE 對比執行計劃
SET AUTOTRACE ON EXPLAIN
SET TIMING ON
SELECT COUNT(*) FROM CASE_GA_AJZLZ; -- 35 萬筆測試表
分析前:全表掃描,Cost 高,Physical Reads 大
分析後:索引快速全掃描 / 索引範圍掃描,Cost 大幅下降,邏輯讀取代替物理讀取
ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS_10; -- 線上交易優先回應前 10 筆
ALTER SYSTEM SET OPTIMIZER_MODE = ALL_ROWS SCOPE=BOTH; -- 批次/報表優先總成本
調優核心轉向「優化等待」。查詢 V$SESSION_WAIT、V$SYSTEM_EVENT 找出系統在等什麼。
| 等待事件 | 含義 | 典型原因 | 對策 |
|---|---|---|---|
| db file sequential read | 單塊讀(索引存取、單塊表存取) | 索引不當、全表掃描、熱塊 | 優化 SQL、增加索引、分區、增大 DB_FILE_MULTIBLOCK_READ_COUNT |
| db file scattered read | 多塊讀(全表掃描、快速全索引掃描) | 大表全掃、缺索引 | 建索引、分區、Materialized View |
| buffer busy waits | 緩衝區忙碌(熱塊爭用) | 熱門索引根塊、Undo 區塊、自由鏈表 | 增加 DB_WRITER_PROCESSES、啟用 ASSM、Hash Partition |
| free buffer waits | 找不到乾淨緩衝區 | DBWR 寫入太慢、緩衝區太小 | 增加 DBWR、啟用非同步 I/O、調大 Buffer Cache |
| log file sync | Commit 等待 LGWR 寫入 Redo | Redo Log 檔案放在慢磁碟、Commit 太頻繁 | Redo 移至快速儲存、批次 Commit |
| latch free | Latch 爭用 | Shared Pool 太小、硬解析多、熱門 SQL | 增加 Shared Pool、使用 Bind Variable、Cursor Sharing |
| enq: TX - row lock contention | 行鎖競爭 | 長交易、無索引外鍵、熱門資料列 | 縮短交易、加外鍵索引、邏輯拆分 |