DB2 优化器在访问多表连接时,会评估是否提前物化部分满足局部谓词的行集合,以缩小后续连接操作的输入规模。opt_enable_partial_data_generation 参数就是控制这一优化行为的开关。它本身不会改写 SQL 语义,但会扩展优化器可选择的计划空间,尤其对星型模型和带有多个过滤条件的事实表连接有直接影响。

参数打开后,优化器可能会在哈希连接或嵌套循环连接之前先生成一个临时结果集,仅包含通过本地过滤条件的数据行。这种部分数据生成策略能否带来收益,取决于事实表过滤后的行数、维表连接键的分布以及临时表空间的 I/O 能力。因此不能简单认为开启就一定能提升性能,需要通过执行计划对比和基准测试来判断。
一、参数的作用机制与适用场景
opt_enable_partial_data_generation 的核心作用是允许优化器在连接阶段之前创建中间结果集。比如事实表有十亿行,查询只关注某个日期范围内的交易,同时还要与客户维表、产品维表做连接。如果优化器先扫描事实表并应用日期过滤,生成一个只有几百万行的部分数据集合,再拿这个集合去连接维表,整体 I/O 和 CPU 开销可能大幅下降。默认情况下,优化器未必会选择这种物化路径,因为它需要考虑临时表空间的写入成本。
该策略在星型模型和多维分析场景中价值最明显。事实表与多张维表连接时,维表通常很小,但过滤条件可能来自维表属性,例如只查询某个地区的客户。如果部分数据生成能够在连接前把事实表范围缩小,后续连接就能避免把大量无关行带入哈希连接或嵌套循环连接。不过,如果过滤条件只来自事实表自身,优化器本来就可以通过索引扫描或表分区裁剪达到类似效果,此时开启该参数带来的提升可能有限。
部分数据生成也会改变执行计划中的操作符组合。常见的计划变化是新增 TEMPTAB 或 SORT 节点,随后连接操作符的输入行数下降。观察访问计划时,如果发现哈希连接的外部输入从全表扫描变成临时表扫描,并且临时表行数远小于原表行数,说明优化器采纳了部分数据生成路径。这种变化既可能减少执行时间,也可能因为临时表写入和排序开销过高而抵消收益。
二、启用步骤与配置检查
该参数通常通过 Db2 实例级注册变量控制。先查看当前是否存在相关设置,可以执行 db2set -all 并过滤 PARTIAL 关键字。如果没有任何输出,说明实例未显式设置该变量,优化器采用默认行为。不同 Db2 版本和补丁级别下默认值可能不同,有的版本默认关闭,有的版本在启用 DB2_WORKLOAD 分析后自动打开部分优化能力。
db2set -all | grep -i PARTIAL
确认需要启用时,使用 db2set 命令设置注册变量。注册变量名通常为大写形式,对应小写参数 opt_enable_partial_data_generation。设置后必须重启实例才能让所有新建连接继承新值。下面是一个完整的启用流程,先设置变量,然后停止并启动实例,最后验证变量是否生效。
db2set DB2_OPT_ENABLE_PARTIAL_DATA_GENERATION=ON db2stop force db2start db2set | grep -i PARTIAL
注意这里使用的是实例级设置,会影响该实例下所有数据库和所有会话。生产环境不要直接在业务高峰期操作,应先在测试实例或至少在一个低负载窗口验证。如果实例上同时运行多个数据库,部分数据生成对某些 OLTP 业务可能产生额外临时空间开销,因此建议按工作负载类型进行分离。
还需要检查临时表空间配置。部分数据生成的结果可能落在内存排序堆或临时表空间中。可以使用 db2 get db cfg 查看 UTIL_HEAP_SZ、SHEAPTHRES_SHR 和临时表空间页大小。若临时表空间不足,启用参数后可能出现排序溢出或临时表空间扩展失败。
三、性能对比与执行计划分析
开启参数后,不能仅凭单次查询变快就得出结论。应当选取典型 SQL 负载,分别在参数关闭和开启状态下生成访问计划并执行基准测试。Db2 的 db2exfmt 工具可以格式化 EXPLAIN 表里的访问计划,方便对比操作符顺序、估计行数和总成本。先运行 EXPLAIN 语句,再用 db2exfmt 输出计划文本。
db2 "CALL SYSPROC.SYSINSTALLOBJECTS('EXPLAIN', 'C', NULL, NULL)"
db2 "EXPLAIN PLAN FOR SELECT ..."
db2exfmt -d sample -g TIC -w -1 -n % -s % -o exfmt_before.txt
上面示例中,EXPLAIN PLAN FOR 后面要替换成实际查询语句。比较计划时,重点关注连接操作符的输入行数变化。如果计划里出现 TEMPTAB 或 SORT 节点,并且连接输入从十亿行降到百万行,说明部分数据生成发挥了作用。如果输入行数没有明显变化,反而多出临时表写入步骤,就需要评估写入成本是否值得。
| 参数状态 | 优化器行为 | 典型风险 |
|---|---|---|
| OFF | 不生成部分中间数据,计划空间较小 | 大连接可能选择全表扫描后连接 |
| ON | 允许物化局部过滤结果 | 临时空间增加,统计信息敏感 |
除了执行计划,还可以使用 db2batch 对比响应时间和资源消耗。建议让同一个 SQL 在参数关闭和开启状态下各执行多次,取稳定值。特别要注意缓冲池命中率、临时表空间读写次数和排序溢出次数,这些指标可以从快照或监控表函数中获取。
四、常见风险与调优建议
部分数据生成的主要风险来自临时空间消耗。优化器在连接前物化中间结果时,可能把大量行写入临时表。如果实例的排序堆和临时表空间配置不足,会触发磁盘排序溢出,导致性能反而下降。启用参数前应先检查 db2 get db cfg 中的 SHEAPTHRES_SHR 和临时表空间容量。若监控发现临时表空间使用率长期超过百分之七十,建议扩展临时表空间或增加缓冲池。
另一个风险是统计信息不准确带来的错误计划选择。部分数据生成会改变优化器的基数估计路径,如果表和索引的统计信息过期,或者列之间存在强关联但未收集列组统计,优化器可能高估或低估物化后的行数。建议在启用参数前先执行 runstats,必要时收集列组统计信息和分布信息。
CALL ADMIN_CMD('RUNSTATS ON TABLE schema.fact_table WITH DISTRIBUTION AND DETAILED INDEXES ALL');
如果启用后大部分查询性能变差,或临时空间压力明显增加,可以回退参数。回退操作同样需要重启实例,并且应保留回退前的执行计划作为基线,方便后续再次调优。设置回退的命令如下。
db2set DB2_OPT_ENABLE_PARTIAL_DATA_GENERATION=OFF db2stop force db2start
最后,不要将多个优化器相关注册变量同时调整。比如 DB2_EXTENDED_OPTIMIZATION、DB2_WORKLOAD 与 DB2_OPT_ENABLE_PARTIAL_DATA_GENERATION 都会影响计划选择,同时修改会让问题定位变得困难。建议一次只改一个参数,用相同负载对比效果,并在测试环境保留配置变更记录。

