runstats 是 IBM Db2 数据库管理系统中一个至关重要的命令,它的主要作用是为数据库管理器收集和更新表的统计信息,这些统计信息是查询优化器制定高效执行计划的基础。

可以把它想象成是给数据库的“导航系统”更新实时路况,如果路况信息(统计信息)过时或不准确,导航系统(查询优化器)就可能为你规划出一条拥堵的路线(低效的查询计划)。
runstats 的核心作用
当你对表进行大量数据操作后(如 LOAD, INSERT, UPDATE, DELETE, REORG),表的物理结构和数据分布会发生变化,旧的统计信息就无法准确反映当前表的真实情况。
runstats 命令通过扫描表的数据,收集以下关键信息:
- 行数: 表中的总行数。
- 页数: 表占用的数据页和空闲页数量。
- 键的基数: 对于索引列,有多少个不同的值,高基数意味着列的区分度高(如
ID),低基数意味着区分度低(如性别)。 - 数据分布: 数据在列上的分布情况,年龄列的数据是均匀分布还是集中在某个区间?这对于选择索引扫描还是表扫描至关重要。
- 索引信息: 索引的唯一性、叶子页数、级别等。
为什么这些信息很重要? 查询优化器使用这些统计信息来:
- 选择访问路径: 决定是使用全表扫描、索引扫描还是其他访问方式。
- 决定连接策略: 选择嵌套循环连接、哈希连接还是合并连接。
- 评估成本: 计算不同执行计划的“成本”,并选择成本最低的一个。
runstats 的目标是确保查询优化器拥有做出最佳决策所需的数据,从而生成最高效的查询执行计划,提升数据库性能。
runstats 的基本语法
runstats 命令的语法非常灵活,可以根据需要进行调整。
最简单的语法
RUNSTATS ON TABLE <schema_name>.<table_name>
这个命令会收集表的基本统计信息,但不会收集任何索引的统计信息。
完整的语法示例
RUNSTATS ON TABLE <schema_name>.<table_name> [ AND INDEXES ALL | (<index_name1>, <index_name2>, ...) ] [ WITH DISTRIBUTION ON COLUMNS (<column_name1>, <column_name2>, ...) ] [ WITH DETAILED INDEXES ] [ WITH SAMPLE <percentage> PERCENT ] [ INCREMENTAL ] [ ALLOW WRITE ACCESS ]
主要参数详解
| 参数 | 说明 | 示例 |
|---|---|---|
ON TABLE <schema.table> |
必需参数,指定要收集统计信息的表。 | RUNSTATS ON TABLE HR.EMP |
AND INDEXES ALL |
强烈推荐,收集该表上所有索引的统计信息,如果不指定,索引信息不会被更新。 | RUNSTATS ON TABLE HR.EMP AND INDEXES ALL |
AND INDEXES (idx1, idx2) |
只收集指定列表中的索引的统计信息。 | RUNSTATS ON TABLE HR.EMP AND INDEXES (PK_EMP, IDX_DEPT) |
WITH DISTRIBUTION ON COLUMNS (col1, col2) |
非常强大,收集指定列的数据分布直方图,对于数据倾斜严重的列(如 STATUS 列,大部分是 'ACTIVE',少数是 'INACTIVE'),这个参数能极大优化查询计划。 |
RUNSTATS ON TABLE HR.EMP AND INDEXES ALL WITH DISTRIBUTION ON COLUMNS (STATUS, DEPT_ID) |
WITH DETAILED INDEXES |
收集更详细的索引统计信息,如索引的碎片程度等,对于索引性能调优很有帮助。 | RUNSTATS ON TABLE HR.EMP AND INDEXES ALL WITH DETAILED INDEXES |
WITH SAMPLE <percentage> PERCENT |
对于超大型表,全表扫描收集 runstats 可能非常耗时,可以使用抽样来只扫描一部分数据(如10%),从而快速完成统计信息收集,这是一种性能与准确性之间的权衡。 |
RUNSTATS ON TABLE HR.EMP AND INDEXES ALL WITH SAMPLE 10 PERCENT |
INCREMENTAL |
增量收集,它不会重置统计信息,而是基于上次的统计信息进行增量更新,这对于频繁变化的表可以显著减少 runstats 的执行时间。 |
RUNSTATS ON TABLE HR.EMP AND INDEXES ALL INCREMENTAL |
ALLOW WRITE ACCESS |
允许在 runstats 执行期间,其他会话对该表进行 INSERT, UPDATE, DELETE 操作,这可以避免锁表,保证业务的连续性。 |
RUNSTATS ON TABLE HR.EMP AND INDEXES ALL ALLOW WRITE ACCESS |
何时需要运行 runstats?
在以下情况后,你应该考虑运行 runstats:
- 数据加载后: 使用
LOAD命令向表中导入了大量数据后。 - 大量数据操作后: 执行了大量的
INSERT,UPDATE,DELETE操作,特别是影响了索引列后。 - 重组表后: 执行了
REORG命令后,表的物理结构发生了改变。 - 创建新索引后: 新的索引需要被统计信息所覆盖。
- 查询性能突然下降: 如果一个原本运行良好的查询突然变慢,可能是由于统计信息过时导致的。
- 定期维护: 作为数据库维护计划的一部分,定期(如每周或每月)对关键业务表执行
runstats。
实践示例
假设我们有一个 HR 模式下的 EMPLOYEES 表,它有一个主键 PK_EMP 和一个部门索引 IDX_DEPT,我们刚刚用 LOAD 命令导入了最新的员工数据。
推荐的 runstats 命令:
-- 连接到数据库 CONNECT TO MYDB USER db2admin USING password; -- 执行 RUNSTATS,收集所有索引的统计信息,并收集关键列的分布信息 RUNSTATS ON TABLE HR.EMPLOYEES AND INDEXES ALL WITH DISTRIBUTION ON COLUMNS (DEPARTMENT_ID, HIRE_DATE, JOB_ID) ALLOW WRITE ACCESS; -- 检查统计信息是否已更新 -- 可以查询 SYSCAT.TABLES 和 SYSCAT.INDEXES 视图中的 CARD 和 STATS_TIME 列 SELECT TABNAME, CARD, LAST_RUNSTATS FROM SYSCAT.TABLES WHERE TABNAME = 'EMPLOYEES' AND TABSCHEMA = 'HR'; SELECT INDNAME, CARD, LAST_RUNSTATS FROM SYSCAT.INDEXES WHERE TABNAME = 'EMPLOYEES' AND TABSCHEMA = 'HR'; -- 断开连接 CONNECT RESET;
注意事项
- 性能影响:
RUNSTATS是一个资源密集型操作,因为它需要扫描表数据,在业务高峰期应避免在大型表上执行全量runstats,优先使用WITH SAMPLE或INCREMENTAL选项。 - 锁: 默认情况下,
RUNSTATS会对表获取一个意向锁,可能会阻塞一些操作,使用ALLOW WRITE ACCESS可以缓解这个问题。 - 不是万能药: 如果查询性能问题是由设计缺陷(如缺少索引、不当的SQL)引起的,
runstats无法解决。 - 版本差异: 不同版本的 Db2 可能在
RUNSTATS的参数和默认行为上略有差异,请参考对应版本的官方文档。
runstats 是 Db2 DBA 和开发人员必须掌握的核心工具之一,正确、及时地使用 runstats 是保证数据库查询性能的关键。
