DB2的查询优化器本质上是一个基于代价的决策器,它需要估算每一条访问路径的成本,然后选出代价最低的方案。而估算成本的核心输入之一就是选择率(Selectivity),也就是一个谓词过滤后大约能留下多少比例的行。选择率估算得准不准,直接决定了执行计划好不好。本文围绕opt_sel_stats这个与选择率统计密切相关的优化方向展开,从原理、参数配置到实战调优逐一分析。

一、选择率估算的底层原理与常见偏差来源
当优化器遇到一个谓词,比如WHERE dept = 'SALES'或者WHERE salary > 50000,它必须回答一个问题:这个条件能过滤掉多少行?DB2在没有详细统计信息时,会退回到内置的默认假设。例如等值谓词默认选择率可能是1/NDISTINCT(不同值个数的倒数),而没有任何统计时甚至直接使用固定比例。这种假设在数据分布均匀时问题不大,但现实业务数据几乎从来不是均匀分布的。
举个典型场景:一张订单表有一亿行,其中status列有10个值,但90%的行状态都是'COMPLETED'。如果优化器只知道NDISTINCT=10,它会假设每个状态各占10%,于是估算status = 'COMPLETED'会返回一千万行,而实际是九千万行。基于这个严重偏低的估算,优化器可能选择嵌套循环连接配合索引访问,结果运行时读取的数据量远超预期,语句跑几十分钟都出不来。这就是数据倾斜(Data Skew)带来的经典问题。
选择率偏差的另一个来源是多列谓词的组合。DB2的基础统计是按单列采集的,当WHERE子句中同时出现city = '北京' AND district = '海淀'时,优化器通常假设两列独立,把两个选择率相乘。但这两列明显相关,独立假设会让估算偏离真实值数倍甚至数十倍。要解决这些问题,就需要让优化器拿到更细粒度的统计信息,这正是opt_sel_stats相关优化的切入点。
二、opt_sel_stats的作用机制与配置方法
opt_sel_stats属于DB2优化器相关的注册变量体系(DB2_REGISTRY / DB2_PROFILE中optimizer相关的配置项),它的设计意图是引导优化器在选择率估算时更充分地利用已采集的详细统计信息,而不是退回到默认启发式假设。启用这类优化器注册变量,通常通过SET CURRENT QUERY OPTIMIZATION搭配注册变量设置完成,典型操作如下:
-- 查看当前优化器相关注册变量 db2 get dbm cfg | grep -i optim -- 设置优化器注册变量(需要实例级权限,设置后需重启实例生效) db2set DB2_OPTIMIZATIONPROFILE=ON -- 在会话级别调整查询优化级别 SET CURRENT QUERY OPTIMIZATION = 9;
需要注意,优化级别(DFT_QUERYOPT)与选择率统计是配合关系。级别5和9在统计信息利用深度上有差异,级别9会考虑更多统计细节和连接枚举顺序,代价是编译时间变长。对于复杂报表查询,级别9往往能带来更优的执行计划;对于高频简单点查,级别5的编译开销更划算。启用opt_sel_stats方向的能力之后,务必确认统计信息本身已经采集到位,否则优化器想用详细统计却没有数据,等于白配置。
另一个关键点是扩展统计(Extended Statistics)。从DB2 9.7开始,RUNSTATS支持采集列组统计信息,用来刻画多列相关性:
-- 对city和district两列采集列组统计,优化器可识别列间相关性
RUNSTATS ON TABLE orders ON COLUMNS ((city, district))
WITH DISTRIBUTION AND DETAILED INDEXES ALL;
-- 查看已采集的列组统计
SELECT COLGROUPCOLS, COLGROUPCARD
FROM SYSCAT.COLGROUPSTATS
WHERE TABNAME = 'ORDERS';
上面的语句会让DB2在系统编目中记录这一列组的组合基数(COLGROUPCARD),优化器估算组合谓词选择率时就不再依赖独立假设,而是直接使用真实组合分布,估算精度可以提升一个数量级。
三、实战调优:从诊断到验证的完整流程
调优的第一步是确认问题确实出在选择率估算上。最直接的手段是对比优化器估算的基数与实际行数,通过EXPLAIN输出可以拿到估算值:
EXPLAIN ALL SET QUERYNO = 100 FOR SELECT * FROM orders WHERE status = 'COMPLETED' AND city = '北京'; -- 查看估算基数 SELECT * FROM EXPLAIN_OPERATOR WHERE QUERYNO = 100; -- 运行后通过监控获取实际基数对比
如果估算基数是500万而实际返回9000万,偏差超过一个数量级,基本可以断定执行计划劣化的根源是统计信息不足。此时的处理顺序是:先跑RUNSTATS WITH DISTRIBUTION采集频率统计(TOP FREQUENT VALUES)和分位数统计(QUANTILES),让优化器感知高频值;对于组合谓词再加列组统计;最后才考虑调整优化注册变量。很多DBA一上来就调参数,方向其实反了,统计信息是根,参数只是让优化器更聪明地使用这些信息。
验证环节同样重要。修改统计策略或参数后,用相同查询重新EXPLAIN,对比新旧执行计划的估算基数和访问路径,必要时用db2batch做稳定的性能基准测试。建议在生产变更时保留一份旧的EXPLAIN输出,方便回退对比。此外要注意统计信息的时效性,数据量变化超过10%到20%时就该考虑刷新统计,否则再详细的统计也会随时间失真。
总结一下,DB2选择率优化是一条完整的链路:先保证RUNSTATS采集了带分布的统计和列组统计,再通过opt_sel_stats这类优化配置让优化器充分利用这些信息,最后用EXPLAIN和实际执行数据闭环验证。把统计信息做扎实,绝大多数所谓优化器选错计划的问题都能得到解决,这比盲目加索引提示或者调高优化级别要可靠得多。
DB2opt_sel_stats选择率统计修改时间:2026-09-08 15:35:14