在 DB2 資料庫中,優化器負責為 SQL 查詢或 DML 語句(INSERT、UPDATE、DELETE)生成訪問計劃。訪問計劃決定了表的訪問順序、索引選擇以及連接方法,其優劣直接影響 SQL 執行效率。DB2 採用基於成本的優化器,依據表與索引的統計信息做出決策。除了基本統計信息外,DB2 還支援收集分布統計信息,這對於處理數據傾斜、重複值高的場景至關重要。本文將詳細闡述分布統計信息的類型、收集方式、優化器如何利用它們,以及參數標記對其效能的影響。
執行 RUNSTATS 可收集基本統計信息,包括:表的頁面數、行數(基數)、溢出行數;列的基數、平均長度、最大/最小值、NULL 值個數等。優化器據此假設數據均勻分布。然而現實中,數據往往存在熱點值或聚集現象。例如某表有 100 萬行,某列只有 10 個不同值,基本統計會估算每值 10 萬行,但實際可能某值佔 90%。此時優化器可能選錯索引,導致計劃次優。分布統計信息正是為了解決此問題而生。
記錄列中出現頻率最高的 N 個值及其出現次數。適用於等值(=)或不等值(<>)謂詞的過濾因子估算。例如 WHERE TYPE = 'A',優化器可精確得知 'A' 的真實選擇率,從而決定是否使用索引掃描。
將列值按升序排列,按固定行間隔採樣,記錄對應值及小於等於該值的行數。適用於範圍謂詞(<、>、<=、>=、BETWEEN)的過濾因子估算。例如 WHERE STATE < 100,優化器能估算出滿足條件的行數比例。預設收集 20 個分位數,估算誤差通常低於 5%。
以 CARS 表為例,100 萬行,99.9% 汽車已完工(STATE=100),僅 1000 輛在製造中。查詢:SELECT * FROM CARS WHERE STATE < 100 AND TYPE = 'A'。
優化器誤判 STATE 均勻分布,選擇 I_TYPE 索引,掃描約 10 萬 RID,實際讀取 99,336 行,耗時 0.53 秒。
優化器識別 STATE < 100 過濾性極高,改用 I_STATE 索引,僅讀取 1,000 行,耗時 0.014 秒,性能提升 36 倍。
使用 RUNSTATS ... WITH DISTRIBUTION 收集。為控制開銷,建議僅對有需求的列收集:
RUNSTATS ON TABLE SAMPLE.CARS WITH DISTRIBUTION ON COLUMNS (TYPE, STATE) AND INDEXES ALLNUM_FREQVALUES(預設 10)和 NUM_QUANTILES(預設 20)查詢 SYSCAT.COLDIST 視圖可驗證是否已收集。重新執行無 WITH DISTRIBUTION 的 RUNSTATS 會清除分布統計。
JDBC PreparedStatement 使用參數標記(?)可避免重複編譯,但優化器在編譯階段看不到具體值,無法充分利用頻率統計信息。實測顯示:使用參數標記時,雖優於無統計信息,但較具體值+分布統計仍慢 8 倍。建議:高頻簡單語句用 PreparedStatement;複雜報表查詢優先用具體值(Statement 或動態 SQL),讓優化器發揮最大效能。
分布統計信息是優化器應對數據傾斜的關鍵武器。DBA 應識別熱點列、非常勻分布列,定期收集頻率與分位數統計;開發人員需權衡 PreparedStatement 的編譯復用優勢與優化器精準估算的需求,根據業務場景選擇最佳實踐。