調優鐵律:測量 → 診斷 → 單一變更 → 驗證 → 固化
「過早優化是萬惡之源」 — 唐納德·克努斯。無基線不調優,無執行計劃不改寫,無統計信息不分析。
DB2 優化器架構與決策鏈
SQL 語句
│
▼
解析器 (Parser) → 語義檢查器 (Semantic Checker)
│
▼
查詢重寫器 (Query Rewrite)
├── 視圖合併、子查詢轉連接、常量折疊、謂詞下推
├── 物化視圖 (MQT) 匹配路由
└── 星型連接轉換、分區剪枝
│
▼
成本基礎優化器 (Cost-Based Optimizer - CBO)
├── 統計信息 (RUNSTATS) → 基數估算
├── 索引匹配 → 訪問路徑選擇 (IXSCAN/TBSCAN/IXAND)
├── 連接方法選擇 (NLJOIN/MSJOIN/HSJOIN)
├── 並行度決定 (INTRA_PARALLEL)
└── 成本模型計算 (CPU/IO/COMM/MEMORY)
│
▼
執行計劃生成 (Access Plan) → 計劃緩存 (Package Cache)
│
▼
執行引擎 (Runtime Engine) → 結果集返回
寫法層面優化:讓優化器「看懂」你的意圖
1. 謂詞構造:索引友好 vs 索引殺手
| ❌ 索引殺手模式 | ✅ 索引友好模式 | 原理 |
WHERE UPPER(name) = 'SMITH' | WHERE name = 'SMITH' (數據標準化) 或 CREATE INDEX idx_upper_name ON t(UPPER(name)) | 函數列導致無法使用列索引 (SARGable 原則) |
WHERE YEAR(date_col) = 2023 | WHERE date_col BETWEEN '2023-01-01' AND '2023-12-31' | 範圍謂詞可用索引區間掃描 |
WHERE col + 10 > 100 | WHERE col > 90 | 列參與運算失去索引性 |
WHERE col IS NULL | 避免或建立 INCLUDE NULL KEYS 索引 | DB2 默認索引不包含 NULL (V9.7+ 可選包含) |
WHERE col LIKE '%abc%' | WHERE col LIKE 'abc%' 或全文索引 | 前導通配符導致全表掃描 |
WHERE col IN (SELECT ... 關聯子查詢) | WHERE EXISTS (SELECT 1 ...) 或 JOIN | EXISTS 半連接優化優於 IN 子查詢 |
WHERE NVL(col, 0) = 0 | WHERE col = 0 OR col IS NULL | 函數包裹破壞 SARGable |
2. 連接寫法優化
-- ❌ 隱式連接 (舊語法,難維護、易錯)
SELECT * FROM a, b WHERE a.id = b.id AND a.type = 'X';
-- ✅ 顯式 ANSI JOIN (清晰語義、優化器更友好)
SELECT * FROM a INNER JOIN b ON a.id = b.id WHERE a.type = 'X';
-- 連接順序提示 (DB2 不支持 HINT,但可通過優化器配置影響)
-- 1. 確保連接列有索引
-- 2. 統計信息準確 (RUNSTATS WITH DISTRIBUTION)
-- 3. 小表驅動大表: 將過濾性強的表放在 FROM 最前 (優化器通常會自動重排)
3. 子查詢重寫策略
| 子查詢類型 | 重寫目標 | 示例 |
| 標量子查詢 (SELECT 列表中) | JOIN + 聚合 或 物化視圖 | SELECT c.name, (SELECT AVG(sal) FROM emp WHERE dept=c.dept) FROM dept c → SELECT c.name, e.avg_sal FROM dept c LEFT JOIN (SELECT dept, AVG(sal) avg_sal FROM emp GROUP BY dept) e ON c.dept=e.dept |
| 相關子查詢 (WHERE 中) | EXISTS / NOT EXISTS / JOIN | WHERE NOT IN (SELECT ...) → WHERE NOT EXISTS (SELECT 1 ...) (NULL 安全) |
| 派生表 (FROM 子查詢) | CTE (WITH) 或 物化視圖 | WITH dept_stats AS (...) SELECT * FROM dept_stats JOIN ... 可複用、可物化 |
4. 排序與分頁優化
-- ❌ 全表排序後取前 N (大表災難)
SELECT * FROM huge_table ORDER BY created_at DESC FETCH FIRST 10 ROWS ONLY;
-- ✅ 索引支持的 Top-N
-- 前提: 存在 INDEX ON huge_table(created_at DESC)
-- 優化器自動使用索引順序掃描 + 早期停止
-- 深分頁優化 (OFFSET 100000 LIMIT 10)
-- 方案 A: 游標分頁 (記住上一頁最大 ID)
SELECT * FROM huge_table WHERE id > :last_max_id ORDER BY id FETCH FIRST 10 ROWS ONLY;
-- 方案 B: 覆蓋索引 + 子查詢
SELECT * FROM huge_table
WHERE id IN (SELECT id FROM huge_table ORDER BY created_at DESC OFFSET 100000 LIMIT 10)
-- 內層只掃描索引鍵,外層回表 10 行
索引設計黃金法則
1. 索引列順序:等值 → 範圍 → 排序 → 覆蓋
-- 查詢: WHERE a=1 AND b>2 AND c=3 ORDER BY d
-- 最佳索引: (a, c, b, d) -- a/c 等值優先,b 範圍,d 排序
-- 覆蓋索引: (a, c, b, d) INCLUDE (e, f) -- 包含 SELECT 列,避免回表
2. 索引類型選擇
| 類型 | 適用場景 | DB2 語法 |
| B-Tree (標準) | OLTP 精確/範圍查詢、排序、分組 | CREATE INDEX ... |
| 壓縮索引 | 大量重複前綴列 (如 URL、路徑) | CREATE INDEX ... COMPRESS YES |
| MDC (多維聚簇) | 數據倉庫多維範圍查詢 | CREATE TABLE ... ORGANIZE BY DIMENSIONS (dim1, dim2) |
| ITC (索引表聚簇) | 熱點表按業務鍵聚簇存儲 | CREATE INDEX ... CLUSTER |
| XML 索引 | XML 列路徑查詢 | CREATE INDEX ... GENERATE KEYS USING XMLPATTERN ... |
| 文本索引 (Net Search Extender) | 全文檢索 | CALL SYSPROC.SYSTS_CREATE(...) |
| 向量索引 (V11.5.7+) | 相似度搜索/RAG | CREATE INDEX ... EXTENSION VECTOR(HNSW, DISTANCE=COSINE) |
3. 索引維護策略
- RUNSTATS 節奏:OLTP 每日增量 (
RUNSTATS ON TABLE ... WITH DISTRIBUTION ON KEY COLUMNS),數倉每周全量
- REORG 觸發:
REORGCHK 指標 F1/F2/F3 > 100 或 REORG_RECOMMENDATION = '*'
- 在線 REORG:
REORG TABLE ... ALLOW WRITE ACCESS (V9.7+),業務零停機
- 廢棄索引清理:
db2pd -db x -indexes 找出 INDEXSCANS=0 且存在 > 30 天的索引
執行計劃深度解讀
獲取計劃三大法
-- 1. EXPLAIN 模式 (靜態/動態)
db2 "EXPLAIN PLAN FOR SELECT * FROM t WHERE id=1"
db2exfmt -d dbname -1 -o plan.txt -g TIC # 格式化輸出
-- 2. db2pd 動態計劃緩存 (運行中 SQL)
db2pd -db dbname -dynamic -apinfo -file /tmp/dyn.sql
-- 3. 活動監控 (V9.7+)
CREATE EVENT MONITOR mon_act FOR ACTIVITIES WRITE TO TABLE;
SET EVENT MONITOR mon_act STATE 1;
-- 運行目標 SQL
SELECT * FROM ACTIVITYSTMT_MON_ACT WHERE STMT_TEXT LIKE '...';
-- 解析 XML 計劃
關鍵算子識別與優化對策
| 算子 | 含義 | 典型原因 | 優化方向 |
| TBSCAN | 表掃描 | 無索引、統計失效、謂詞非 SARGable、小表 | 創建索引、重寫謂詞、RUNSTATS、小表可忽略 |
| IXSCAN | 索引掃描 | 正常,但檢查是否為全索引掃描 (無 START/STOP KEY) | 優化謂詞順序、添加 INCLUDE 列覆蓋 |
| SORT | 排序 | ORDER BY/GROUP BY/DISTINCT/UNION/連接輸入排序 | 索引順序消除排序、增加 SORTHEAP、避免大排序 |
| HSJOIN | 雜湊連接 | 大表連接、無索引、非等值連接 | 確保連接列有索引、考慮 NLJOIN/MSJOIN、調整 SORTHEAP |
| NLJOIN | 嵌套循環連接 | 小表驅動大表、外表有索引 | 通常最優,檢查內表索引是否命中 |
| MSJOIN | 合併連接 | 兩輸入已排序、等值連接 | 優於 HSJOIN,確保輸入有序 (索引/排序) |
| TEMP | 臨時表物化 | 複雜子查詢、派生表、排序溢寫 | 重寫為 CTE/JOIN、增加 SORTHEAP/TEMP 空間 |
| FILTER | 後置過濾 | 索引無法完全應用謂詞 | 優化索引列順序、添加 INCLUDE 列 |
統計信息:優化器的「眼睛」
-- 基礎收集 (快速)
RUNSTATS ON TABLE schema.table WITH DISTRIBUTION ON KEY COLUMNS AND DETAILED INDEXES ALL;
-- 全量收集 (準確,耗時長)
RUNSTATS ON TABLE schema.table WITH DISTRIBUTION ON ALL COLUMNS AND DETAILED INDEXES ALL ALLOW WRITE ACCESS;
-- 系統級自動收集 (STMM 配合)
UPDATE DB CFG USING AUTO_RUNSTATS ON AUTO_STMT_STATS ON AUTO_STATS_VIEWS ON;
-- 統計信息導出/導入 (跨環境復現)
CALL SYSPROC.EXPORT_STATS('DBNAME', '/tmp/stats', 'C');
CALL SYSPROC.IMPORT_STATS('DBNAME', '/tmp/stats', 'C');
配置參數對性能的杠桿作用
| 參數 | 調優方向 | 典型值範圍 | 影響維度 |
| SORTHEAP | 調大防止排序溢寫 | 1000-10000 (4KB 頁) | 排序、雜湊連接、索引創建 |
| SHEAPTHRES_SHR | 共享排序閾值 = SORTHEAP * 並發排序估算 | SORTHEAP * 10-50 | 並發排序內存保護 |
| LOCKLIST | 調大防止鎖升級 | 10000-100000 (4KB) | 並發、死鎖、鎖等待 |
| MAXLOCKS | 配合 LOCKLIST 調高 | 80-95 | 單應用鎖佔用上限 |
| PCKCACHESZ | 調大減少編譯開銷 | AUTOMATIC 或 20000+ | 動態 SQL 編譯緩存命中率 |
| DFT_DEGREE | 啟用查詢並行 | ANY (配合 INTRA_PARALLEL=ON) | 大查詢並行度 |
| NUM_IOSERVERS | 匹配磁盤陣列數 | 物理磁盤數 / CPU 核心數 | 預取並行度 |
| CHNGPGS_THRESH | 異步寫入觸發閾值 | 40-60 (默認 60) | 髒頁刷新平滑度 |
調優實戰檢查清單 (按 ROI 排序)
- 統計信息:
RUNSTATS 全量 + 分佈 — 成本最低、收益最高
- 索引缺失:
db2advis / EXPLAIN 找 TBSCAN/SORT → 創建索引
- 謂詞重寫:消除函數列、前導通配符、隱式轉換 — 零成本、即時生效
- 內存參數:SORTHEAP/LOCKLIST/PCKCACHESZ — 動態生效、立竿見影
- 並行度:INTRA_PARALLEL + DFT_DEGREE=ANY — 大查詢加速明顯
- 分區/MDC:大表範圍查詢 — 架構級優化、需規劃
- MQT/物化視圖:重複聚合查詢 — 預計算換空間換時間
- 應用邏輯:批量操作、減少往返、連接池 — 代碼層面、收益最大
總結
SQL 性能調優是 統計信息準確性、索引設計合理性、寫法 SARGable 化、配置參數適配性 四大支柱的系統工程。DB2 提供了完整的工具鏈 (RUNSTATS/db2advis/EXPLAIN/db2pd/db2top/活動監控) 支持科學調優。核心心法:
信數據、信計劃、信工具、信迭代。
每次只改一處,驗證效果,固化最佳實踐。
調優無終點,只有在當前業務負載下的「足夠好」。
- 上一篇文章: DB2 跨版本遷移關鍵技巧:db2look 版本差異與 DDL 完整提取實戰
- 下一篇文章: Visual C# 連接 DB2 實戰:OLE DB Provider 架構下的數據訪問完整指南
Copyright ©
程式碼之家 All Rights Reserved