我有个朋友:最近一次投产后一个业务系统发生了性能下降问题,研发和生产对问题产生的原因存在分歧。和朋友聊过之后,觉得这个问题还比较有参考价值,在征得他的同意后,我把相关情况整理发在这里。
问题经过
该系统投产时需要调整表结构,命令如下:
db2 "alter table NOR.T08LIST_INFO add column dobject_id varchar(128)"
db2 "alter table NOR.T08LIST_INFO alter resolve_type set data type varchar(1000)"
可以看到,对NOR.T08LIST_INFO这张表增加了一个新字段dobject_id,对存量字段resolve_type进行了长度扩容。
执行变更后,对该表进行了统计信息更新(RUNSTATS)。在应用验证阶段,单个用户登录操作未体现出性能问题。
第二天上午8点左右,业务高峰期,部分调用该系统接口的业务出现缓慢情况。
数据库活动连接数急剧增加,锁等待现象加剧,同时表现为高IO和高CPU使用率。发现是数据库对这张表的访问有大量的锁等待。
首先检查该表上的锁,发现存在300多个活动连接。经确认业务出现挂起且连接无响应现象,遂强制终止所有相关应用程序连接,以防止业务连接再次暴增,随后停止应用程序。
停止应用程序后,对该表进行了重组(REORG)及统计信息更新(RUNSTATS),总耗时约4分钟。
随后重新启动应用程序,并通知各访问端进行验证。
反馈业务恢复正常。
分歧点
生产同事认为对表新增字段或是字段类型调整应该需要做reorg。
研发同事认为之前投产也做过类似的修改表结构操作后没有做reorg,没出现过问题,应该和修改表结构操作无关。
那么原因究竟是什么呢?
驻场工程师在测试环境拿生产投产前的全量备份恢复了一个数据库出来,按照投产方案也在测试环境进行了相同的操作,找了二线专家来分析,判断问题出在Package上。
分析过程
在表结构修改之前,查询了数据库的无效包。
db2 "select pkgname,valid from syscat.packages where valid != 'Y' with ur"
总计86个。
然后执行了添加字段操作,并查询无效包:
db2 "alter table NOR.T08LIST_INFO add column dobject_id varchar(128)"
db2 "select pkgname,valid from syscat.packages where valid != 'Y' with ur"
总计97个,增加了11个。
再对表字段进行扩容,并查询无效包:
db2 " alter table NOR.T08LIST_INFO alter resolve_type set data type varchar(1000)"
db2 "select pkgname,valid from syscat.packages where valid != 'Y' with ur"
总计102个,又增加了5个。
总共增加16个无效包。
与最新生产环境对比,的确多了16个无效包。
官方解释
DB2 的行为机制:
当表结构发生变化(如增加字段、修改字段类型等),与该表相关的 package 会失效。
失效的 package 在首次被使用时,会触发隐式的 REBIND 操作。
隐式 REBIND 操作会占用系统资源,尤其是在高并发场景下,可能导致锁争用和性能下降。
这个跟监控工具里当天上午8点左右锁等待很高的现象吻合。
优化建议
在对表做了alter后,最好立刻对相关的package做rebind操作。
db2 "rebind package <package_name>"
如果不确定是哪个包,就执行:
db2rbind db_name -l cc.log all
要注意在业务空闲时候做。
那Reorg究竟要不要做?
在 DB2 数据库中,加字段(ADD COLUMN)操作通常不需要立即执行表重组(REORG),数据库会为新字段分配存储空间。
但太大的varchar类型可能会导致行溢出,导致数据被拆分存储。这会增加 I/O 操作,逐渐影响性能,但通常不会像锁争用那样突然导致严重的性能问题
所以执行 REORG 可以优化数据的物理存储,消除碎片化,提高访问效率。
总结
在 DB2 中,表结构修改后,依赖该表的静态 SQL 包(Package)会被标记为无效(Invalid),因为执行计划可能不再适用。此时需要显式重新绑定(rebind)以确保 Package 重新编译并生成新的执行计划。
当 Package 失效后,如果应用程序尝试使用这些 Package,DB2 会尝试隐式 rebind。在高并发场景下,隐式 rebind 会导致锁争用(如 sysibm.sysplan 被锁),从而引发性能问题。
注意:以上针对静态SQL。




