DB2的表在经历大量插入、更新和删除之后,物理存储结构会逐渐变得混乱:数据页出现空闲碎片、索引失去聚簇属性、表中的统计信息与真实数据严重脱节。这些变化不会立刻报错,却会悄悄拖慢每一条SQL的执行速度。要解决这类问题,靠的就是RUNSTATS和REORG这两个经典工具的配合使用。本文从原理入手,讲清楚它们各自负责什么、为什么必须搭配执行,以及在生产环境中的落地方法。

一、RUNSTATS和REORG分别解决什么问题
很多DBA容易把这两个命令混为一谈,其实它们的职责完全不同。RUNSTATS是一个信息采集工具,它扫描表和索引,把行数、列的数据分布、索引的键值分布、页的空闲情况等统计信息写入系统编目表。DB2的优化器在解析SQL时,正是依赖这些编目中的统计信息来判断走索引扫描还是表扫描、多表连接时谁先谁后。如果统计信息停留在一年前,而表的数据量已经翻了几十倍,优化器生成的执行计划很可能完全错误。
REORG则是物理层面的整理工具。它对表空间或索引进行重构,把散落在各处的数据行重新紧凑排列,回收删除操作留下的空闲页,恢复索引的聚簇顺序(CLUSTER RATIO),必要时还可以重置自由空间比例(PCTFREE)。一个碎片率很高的表,即使统计信息是新的,优化器选出了正确的访问路径,实际执行时也要读取远多于必要的数据页,I/O开销依然很大。
简单总结:RUNSTATS影响优化器的判断,REORG影响数据实际读取的效率。一个管决策,一个管执行,缺了任何一个,性能优化都不完整。
二、为什么REORG之后必须紧跟RUNSTATS
这是实际运维中最容易被忽略的一个环节。REORG执行完毕后,表的物理结构发生了巨大变化:页的数量减少、空闲空间分布改变、索引的聚簇比例大幅提升。此时编目表里保存的还是REORG之前的旧统计信息,如果不再执行一次RUNSTATS,优化器手里的数据与表的真实状态依然不匹配。
举个典型场景:一张订单表REORG前碎片率高达60%,统计信息记录的溢出行数量很大。REORG之后溢出行几乎清零,但因为没刷新统计信息,优化器仍然认为访问这张表需要大量额外的页读取,于是放弃了一个本来很优秀的索引。这种情况下REORG带来的物理收益就被白白浪费了。
所以标准的执行顺序应该是:REORG TABLE → RUNSTATS → 重新绑定相关包。第三步也常被遗忘,因为静态SQL的执行计划是在包绑定时固化的,统计信息更新后需要让旧包重新生效。基本命令如下:
-- 整理表及其索引
REORG TABLE orders INDEX orders_idx1;
-- 采集表和所有索引的统计信息
RUNSTATS ON TABLE db2inst1.orders
WITH DISTRIBUTION AND DETAILED INDEX ALL;
-- 让静态SQL包重新利用新统计信息
REBIND PACKAGE db2inst1.pkg_orders;
注意WITH DISTRIBUTION选项会额外采集列值的分布信息,对数据倾斜严重的列(比如状态字段只有几个取值)非常关键,没有分布信息时优化器只能假设数据均匀分布,容易做出错误判断。
三、如何判断哪些表需要RUNSTATS和REORG
盲目对全库几百张表执行REORG是低效且危险的,REORG会持有排他锁,在线业务高峰期执行可能直接锁表。DB2提供了系统视图来定位最需要维护的对象,核心是SYSIBMADM.SNAPTAB和SYSIBMADM.ADMINTABINFO。
SELECT TABSCHEMA, TABNAME,
PAGE_REORGS, -- 累计重组页数
OVERFLOW_ACCESSES -- 溢出行访问次数
FROM SYSIBMADM.SNAPTAB
WHERE OVERFLOW_ACCESSES > 10000
ORDER BY OVERFLOW_ACCESSES DESC;
判断标准通常有两条:一是溢出记录访问次数高,说明表存在大量变长更新导致的行迁移;二是索引聚簇比例低于90%左右,说明数据物理顺序与索引顺序偏离严重。可以通过下面的语句查看:
SELECT INDNAME, CLUSTER_RATIO, STAT_TIME FROM SYSCAT.INDEXES WHERE TABSCHEMA = 'DB2INST1' AND TABNAME = 'ORDERS';
STAT_TIME列还能告诉你统计信息最后一次刷新是什么时候,如果距今超过一个月且表变更频繁,就应该安排RUNSTATS了。UPDATE类型的变更越多,越需要关注PCTFREE参数——REORG时适当调大PCTFREE,可以给未来的更新留出页内空间,减少行迁移,延长REORG的效果周期。
四、生产环境自动化维护方案
手工逐条执行命令只适合小规模环境,生产库推荐用DB2内置的AUTO_MAINT自动维护策略,或者编写脚本定期巡检。自动维护的开启方式如下:
-- 启用自动表维护 UPDATE DB CFG FOR MYDB USING AUTO_MAINT ON; UPDATE DB CFG FOR MYDB USING AUTO_TBL_MAINT ON; UPDATE DB CFG FOR MYDB USING AUTO_RUNSTATS ON; UPDATE DB CFG FOR MYDB USING AUTO_REORG ON;
自动维护策略会根据表的活动情况自行决定何时执行RUNSTATS和REORG,并且支持在线模式,减少对业务的影响。不过自动REORG比较保守,碎片严重的表有时需要人工介入。对于这类情况,可以写一个shell脚本,在业务低峰期批量处理:
#!/bin/bash
# 从维护清单中读取表名,逐个执行重组和统计采集
while read -r SCHEMA TABLE
do
db2 "REORG TABLE ${SCHEMA}.${TABLE} ALLOW NO ACCESS"
db2 "RUNSTATS ON TABLE ${SCHEMA}.${TABLE} WITH DISTRIBUTION AND INDEX ALL"
echo "${SCHEMA}.${TABLE} done at $(date)" >> /db2_home/maint.log
done < /db2_home/reorg_list.txt
几点实操建议:REORG尽量安排在维护窗口,使用ALLOW WRITE ACCESS在线选项时要注意日志空间是否充足,在线REORG产生的日志量可能很大;REORG的临时排序需要足够的工作表空间,执行前确认SMS或DMS表空间有剩余容量;大表REORG可以分步执行,先做REORG INDEXES ALL缩短单次锁定时间;最后别忘了REBIND相关包,让新的统计信息真正被静态SQL利用起来。
把RUNSTATS和REORG纳入周期性维护计划,配合系统视图的巡检指标持续跟踪,是保证DB2长期稳定性能成本最低的手段。与其等业务反馈查询变慢再排查,不如让这两条命令形成固定流程,防患于未然。
DB2 RUNSTATSDB2 REORG表维护修改时间:2026-09-05 23:54:47