在DB2数据库中,查询优化器依赖统计信息生成执行计划,其中基数估计决定了中间结果集的大小,进而影响连接方法、访问路径以及排序策略的选择。当统计信息偏离实际数据分布时,即使SQL语句写法简洁,执行计划也可能变得低效。DB2提供的SYSPROC.OPT_CARD_STATS存储过程允许管理员在会话或全局层面手动覆盖基数估计,是应急优化和特殊场景下的有效工具。本文将从原理、使用方法和验证三个角度展开,帮助读者掌握利用OPT_CARD_STATS修正基数统计的技巧。

基数统计影响执行计划的原理
执行计划的核心是连接顺序和访问方法的选择。优化器会为每个可能的执行步骤估算返回行数,也就是基数。例如,对于两个表的连接,如果其中一个表的过滤条件具有高度选择性,优化器可能选择它作为内表并使用索引访问;但如果估算的过滤后行数偏大,优化器可能错误地选择全表扫描或哈希连接。因此,基数估计的准确性直接决定了执行计划的质量。在日常运维中,RUNSTATS负责收集表的统计信息,但某些情况下统计信息可能无法及时更新,或者数据分布过于倾斜导致单一统计值不能反映真实情况。
DB2提供OPT_CARD_STATS存储过程,就是为DBA提供一个人工干预基数估计的入口。该过程允许为特定表设置总行数,也可以为特定列设置不同值数量。调用后,优化器在生成计划时会优先使用这些手动指定的基数,而不再依赖RUNSTATS收集的统计信息。这种机制特别适合快速修正因统计信息过期、数据倾斜严重或查询条件特殊导致的错误估计。需要注意的是,OPT_CARD_STATS并不会更新系统目录中的统计信息,它只是影响优化器的运行时判断,因此不会改变SYSCAT.TABLES或SYSCAT.COLUMNS里的记录。
手动设置基数时,如果列名参数传入NULL,则表示设置表级的总行数;如果指定列名,则设置该列的不同值数量。例如,某张员工表实际有200万行,但RUNSTATS收集到的是50万行,优化器会低估中间结果集大小,可能错误地选择嵌套循环连接。通过OPT_CARD_STATS将表级基数设置为200万后,优化器就会基于正确的规模重新生成计划。
使用OPT_CARD_STATS调整基数统计的典型场景与调用方法
OPT_CARD_STATS最常见的应用场景包括:数据倾斜严重的列、表函数或昵称缺失统计信息、联邦查询中远程表基数不准确,以及生产环境无法立即执行RUNSTATS时的临时修复。以数据倾斜为例,某列中某个值的行数占比极高,而整体不同值数量又很小,优化器可能认为该列的过滤选择性很强,但实际上过滤条件恰好命中了倾斜值,导致返回大量行。此时单独依赖RUNSTATS的列统计很难精确描述这种分布,DBA可以通过设置该列的基数或直接调整表级基数来纠正。
调用语法相对简单,使用CALL语句执行存储过程。下面是一个设置表级基数的示例:
-- 将表 EMPLOYEE 的总行数估计调整为 2000000
CALL SYSPROC.OPT_CARD_STATS('DB2INST1', 'EMPLOYEE', NULL, 2000000);如果需要调整某列的不同值数量,可以将列名作为第三个参数传入:
-- 将列 DEPT_ID 的不同值数量调整为 50
CALL SYSPROC.OPT_CARD_STATS('DB2INST1', 'EMPLOYEE', 'DEPT_ID', 50);调用完成后,动态SQL语句会立即使用新的基数估计。对于已经绑定的静态SQL包,需要重新绑定或执行相应的REBIND操作才能让优化器重新生成计划。此外,该存储过程的影响范围通常是数据库级别的,多个会话都会看到调整后的基数,因此在使用时需要谨慎,避免对不相关的查询产生负面影响。如果希望清除手动设置并恢复使用RUNSTATS统计信息,可以将基数参数设置为NULL或负值,具体用法可以参考对应DB2版本的官方文档。
验证优化效果与注意事项
调整基数后,需要通过执行计划验证优化器是否采用了更合理的访问路径。可以使用EXPLAIN PLAN FOR语句生成计划,然后查询EXPLAIN_STREAM或其他计划表查看估算成本。下面是一个基本的验证流程:
-- 为查询生成执行计划 EXPLAIN PLAN FOR SELECT * FROM EMPLOYEE WHERE DEPT_ID = 50; -- 查看优化器预估的基数信息 SELECT O.OPERATOR_TYPE, S.TARGET_NAME, S.OBJECT_SCHEMA, S.OBJECT_NAME, S.CARDINALITY FROM SYSTOOLS.EXPLAIN_OPERATOR O JOIN SYSTOOLS.EXPLAIN_STREAM S ON O.EXPLAIN_TIME = S.EXPLAIN_TIME AND O.OPERATOR_ID = S.SOURCE_ID WHERE O.EXPLAIN_TIME = (SELECT MAX(EXPLAIN_TIME) FROM SYSTOOLS.EXPLAIN_OPERATOR) ORDER BY O.OPERATOR_ID;
更直观的方式是使用db2exfmt工具生成格式化的计划报告,对比调整前后预估行数的变化。如果调整后优化器选择了索引访问或改变了连接顺序,说明基数修正起到了预期效果。同时,也需要观察实际查询的响应时间和资源消耗,确认执行计划确实得到改善。
使用OPT_CARD_STATS时需要注意几个关键点。首先,手动设置会覆盖真实统计信息,如果后续数据分布发生变化,而DBA忘记更新或清除手动设置,优化器可能长期基于错误的基数生成计划。因此建议将手动设置作为临时措施,并记录下来以便后续清理。其次,该过程并不替代RUNSTATS,对于大规模数据变更,仍然需要定期执行RUNSTATS以保持统计信息的新鲜度。最后,不同DB2版本中OPT_CARD_STATS的参数边界和清除方式可能存在差异,实施前应查阅对应版本的官方文档,避免因版本差异导致预期之外的行为。
DB2 opt_card_stats基数统计执行计划优化修改时间:2026-08-26 12:15:20