简介:这份文档面向DB2数据库运维DBA与性能调优学习者,记录某银行DB2系统SQL执行变慢、ACTIVE SESSION异常增多的真实排查案例,核心聚焦系统临时表空间TEMPSPACE1膨胀至10GB所引发的性能问题。资源包共1个doc文件,约607KB,内容涵盖性能问题初步确认、LATCH分析方法、STACK收集与分析技巧,以及用db2trc工具暂停实例抓取诊断信息等实操手段,并给出SQL优化、参数调整与临时表空间清理的解决思路。已有5903人学习下载,适合希望积累真实故障定位经验、掌握DB2性能诊断工具的读者参考借鉴。
1. 临时表空间:为什么一个“没人管”的 10G 文件能拖垮整库
一个几乎没人关注的系统临时表空间,从 0 悄悄涨到 10G,然后整库的 SQL 开始变慢、活动会话数从个位数飙到几十个——这件事最反直觉的地方在于:慢的 SQL 本身没变,执行计划没变,CPU、内存、I/O、锁等待、缓冲池命中率全都正常。常规排查一圈下来毫无收获,真正的元凶藏在一个平时连看都不看的 TEMPSPACE1 里。DB2 临时表空间过大引发的性能问题,本质不是“空间不够”,而是“空间太大”反过来把内部元数据操作拖慢,再通过 LATCH 竞争把等待放大到所有并发查询上。搞懂这条链路,你才能明白为什么扩容、加索引、优化 SQL 全都治不好它,也才能在下一次遇到“指标全绿但就是慢”时,知道该往哪个黑匣子里翻。
2. 现象层排查:为什么常规指标全部正常却依然慢
2.1 ACTIVE SESSION 数量是第一个可信信号
业务反馈“系统变慢”这件事本身不可全信,应用层、网络层、用户感知都可能造成偏差。但数据库监控里 ACTIVE SESSION 数量频繁突破 50,这就是硬信号了。这个指标的含义是当前正在处理 SQL 请求的会话数,涵盖 Compiling、UOW Executing、Lock Waiting、Commit Active,以及启用并发限制后排队中的 Queued 状态。换句话说,只要一个会话还在“干活或等活”,它就计入其中;而执行完一条语句、下一条还没开始的 UOW Waiting 状态不计入。
这个区分很关键。平时 OLTP 系统的活动会话通常在 10 个以内,繁忙系统二三十个。当它从个位数突然频繁冲到几十,只有两种可能:业务量真的涨了,或者 SQL 执行时间变长了导致会话堆积。和业务方确认访问量没有增加,那就基本锁定是数据库侧的性能问题。进一步在会话页面看状态,发现活动会话几乎全是 UOW Executing——不是锁等待,不是排队,就是实打实在执行,只是执行得太久。
2.2 快速排除法排掉了哪些嫌疑
确认是数据库自身问题后,第一轮排除做得很快:CPU 利用率正常,操作系统内存正常,缓冲池命中率正常,没有 LOCK WAIT,从平均物理读时间、直接读时间、物理写时间、直接写时间四个参数看 I/O 也正常。死锁累计值 218 但不影响当前性能,排序溢出 10 次略高,但应用 SQL 本来排序就多,不足以解释全局变慢。
这一轮排除的价值不在于找到原因,而在于划掉了一大片区域。资源没瓶颈、锁没冲突、I/O 没抖动、缓冲池没失效,那么慢一定来自某个“执行路径上的额外开销”。这时候如果直接跳去优化 SQL,就容易翻车——因为你会优化那些“看起来慢”的语句,却解释不了“为什么以前不慢、现在慢”。
2.3 抓慢 SQL:两种视图各有盲区
抓执行时间长的语句用了两条路。一条是包缓存里的动态 SQL 按平均执行时间排序,看到最长的接近 4 秒,但执行次数都只有几次——这暴露了应用直接拼凑 SQL 字符串、不走变量绑定的问题,几乎每条语句对 DB2 都是新语句,缓存统计样本很薄。另一条是用当前 SQL 管理视图抓正在执行的语句,按已运行时间排序,一次能抓到接近 30 条,和活动会话数对得上。
这里有个容易忽略的细节:抓当前 SQL 时语句还没跑完,显示的已运行时间比完整执行时间短,而且需要多抓几次才能撞上高峰。更细的时间分布要靠包缓存表函数,它能给出总等待时间、锁等待时间、排序时间等,并算出各项占总执行时间的百分比。结果里有一批 with 开头的语句,等待占比高达 95% 以上,但等待的不是读、不是锁、不是日志、不是排序——这就把矛头指向了一个平时不在监控面板上的东西:LATCH。
3. LATCH 机制:DB2 内部那把“轻量锁”为什么会成为瓶颈
3.1 LATCH 到底是什么,和 LOCK 差在哪
DB2 文档里几乎找不到对 LATCH 的系统介绍,但可以这样理解:它是为了保证多线程访问内部共享数据结构的一致性而存在的轻量同步机制。举个具体例子,内存里有一个预取队列,处理用户请求的协调线程往里加预取任务,多个预取线程不停从里面取任务,为了协调这两类线程对同一个队列的访问,每次访问前都要先拿一个 LATCH,拿不到就等。
它和 LOCK 的区别在于作用域和粒度:LOCK 保护的是用户数据(行、表),用户能看见、能干预、能通过隔离级别调整;LATCH 保护的是 DB2 内部结构(内存池、表空间元数据、缓冲区链),用户看不见、不能直接调,只能通过间接指标观察等待时间。也正因为如此,LATCH 竞争一旦发生,从应用侧看就是“SQL 无缘无故变慢”,从监控侧看就是“各项资源指标都正常”。
3.2 用 db2pd 抓 LATCH 现场:为什么要持续采样
第一轮用 LATCH 检查命令扫了一遍,没发现异常——这很正常,因为 LATCH 等待往往只持续几秒就消散,单次快照很容易错过。改成带间隔重复输出的方式持续观察,才抓到重大异常:某个 EDU 持有 pool_table_latch,同时有 23 个 EDU 在等它。这意味着一个操作卡住,直接让至少 24 个会话处于活动状态,活动会话数瞬间被推高。
这一步的排查经验值得记住:瞬时指标正常不代表没有问题,对于“间歇性、短时、高并发”的竞争,必须用重复采样去撞概率。采样间隔和次数要根据现象持续时间来定,间隔太长会漏,太短会自己给系统加压。
3.3 从 LATCH 名字读不出信息时,靠 STACK 反推调用链
pool_table_latch 这个名字字面意思是“池表锁”,但具体保护什么、谁在什么场景下持有,没有公开资料。等待几秒就消失,也来不及抓持有者和等待者当时在干什么。这时候的突破口是 STACK 收集:db2pd 在收集各 EDU 堆栈的同时,会把当时的 LATCH 信息和 LOCK 信息一并记下来,正好能把“谁持有、谁在等”和“它们各自执行到哪个函数”对应上。
收集命令指定了输出目录和重复次数,比如每 3 秒收一次、连续收 10 次,因为现象不是一直存在,需要持续撞。收完后在结果文件里搜 LATCH 名字,确认抓到了持有和等待的记录,再进对应文件看堆栈。这里必须提醒:生产环境繁忙时收集 STACK 会明显消耗资源、影响性能,属于“必要但要谨慎”的手段,尽量选影响可控的窗口。
4. 源码级线索:从 STACK 函数名还原 pool_table_latch 的争用链
4.1 持有者堆栈指向表空间快照
持有 LATCH 的 EDU 堆栈里,能看到一串函数调用:从表空间快照入口,到监控 SMS 表空间时获取容器数据页的函数,底层还落到文件查找相关调用。把这些函数名按字面意思串起来,可以还原出这个线程正在做的事——对表空间做快照,并且在统计 SMS 表空间的容器页信息。它持有 pool_table_latch 的时间偏长,正是因为要遍历容器、读取页数据。
Holder EDU 调用链(节选,函数名保留原样便于对照) sqlmonssagnt <- 监控代理入口 sqlbSnapshotTablespace <- 对表空间做快照 sqlbMonSMSGetContainerPages <- 统计 SMS 表空间容器页 SQLB_FIND_BUF::next <- 遍历文件查找缓冲 sqlofindn2 / __xstat64 <- 底层文件状态查询这段调用链的解释是:快照操作本身要访问表空间的元数据和容器文件,而容器数量、文件状态查询的开销会随着表空间规模增长。表空间越大、容器文件越多,这个“统计容器页”的动作就越慢,持有 LATCH 的时间就越长。这就是“临时表空间过大”和“LATCH 被长时间持有”之间的第一层因果。
4.2 等待者堆栈指向临时表创建
等待 LATCH 的 EDU 堆栈则是另一条链:从表创建临时表的入口,到内部创建表,再到获取系统临时数据池,上层还能看到谓词求值和取数相关函数。这条链说明等待者正在执行一条查询 SQL,查询过程中需要创建内部临时表、使用系统临时表空间,而这一步要拿 pool_table_latch,于是被持有者堵住。
Waiter EDU 调用链(节选) sqlriFetch / sqlrita <- 查询取数 sqldEvalDataPred <- 谓词求值 sqldTableCreateTemp <- 创建临时表 sqldInternalCreateTable <- 内部建表 sqlbGetSysTempDatapool <- 获取系统临时数据池(此处等 LATCH) SQLO_SLATCH_CAS64::getConflict <- 自旋/冲突等待两条链一对照,机制就清楚了:监控代理周期性对表空间做快照,快照在超大临时表空间上耗时变长,长时间持有 pool_table_latch;与此同时,业务查询因为要用临时表,创建临时表时必须拿同一把 LATCH,于是排队等待。等待时间被计入 SQL 执行时间,活动会话堆积,表现为整库变慢。慢的不是某一条 SQL 的逻辑,而是它们共同撞上了同一把内部锁。
4.3 analyzestack:把散落的堆栈汇总成统计
手工翻几十个堆栈文件效率很低,DB2 安装目录下带了一个 Perl 脚本,能把指定目录里所有堆栈文件中相同的堆栈汇总统计,并单独做 LATCH 分析,输出两个结果文件。它的参数大致是:指定对比堆栈时比较的函数个数、指定堆栈文件所在目录或具体文件、开启 LATCH 分析。这个脚本原本是支持部门内部工具,声明为“按原样提供、无官方支持”,所以用法只能靠帮助参数自己摸索。
# 汇总目录下所有堆栈文件并做 LATCH 分析 perl ~/sqllib/pd/analyzestack -d 50 -i /tmp/stack0531 -l # -d 比较函数个数,-i 堆栈目录,-l 开启 LATCH 分析 # 输出 LatchAnalysis.out 与 StackAnalysis.out它的价值在于把“某一次采样里谁等谁”升级成“多次采样中哪类堆栈反复出现”,从而确认这不是偶发现象,而是稳定复现的争用模式。对于定位这类间歇性问题,统计比单点更有说服力。
5. 避坑与排查:这类问题最容易踩的五个坑
5.1 只重启实例,临时表空间不释放
现象:做完一轮处理后重启数据库实例,临时表空间大小没变,慢查询依旧。原因:SMS 临时表空间里的临时数据文件在特定条件下会遗留,实例重启不会清理这部分状态,必须对数据库做去激活再激活,才能让临时表空间被真正释放。解决:安排维护窗口执行数据库级去激活/激活,之后确认表空间大小回落、表空间列表命令恢复秒级返回。这个坑的血泪经验是:动作要对准机制,重启实例和重启数据库不是一回事。
5.2 看到慢 SQL 就一头扎进 SQL 优化
现象:创建索引解决了几个全表扫描,又去梳理复杂长 SQL,但整体变慢没有缓解。原因:慢的根因不在 SQL 逻辑,而在内部 LATCH 争用,优化单条 SQL 改变不了“大家抢同一把锁”的局面。解决:先用包缓存表函数看等待时间占比,如果等待占比极高且不属于读、锁、日志、排序,就先转向 LATCH 方向排查,别在 SQL 文本上耗时间。
5.3 单次 LATCH 快照没异常就下结论
现象:第一次检查 LATCH 显示正常,差点排除这个方向。原因:等待只持续几秒,单次快照撞上的概率很低。解决:用带间隔的重复采样持续观察,采样间隔和次数按现象持续时间设定,抓到“一个持有者、多个等待者”的模式才算证据。
5.4 在生产高峰收集 STACK
现象:收集堆栈期间数据库更慢,业务投诉增加。原因:堆栈收集要暂停线程、抓取调用链,本身开销不小。解决:选低峰窗口,控制重复次数,收完立即停止;把收集目录指到独立路径,避免和诊断目录混在一起影响后续分析。
5.5 忽略监控代理的周期性动作
现象:问题呈周期性出现,但找不到业务侧的对应操作。原因:数据库监控代理会定期采集表空间信息,这个动作在超大表空间上变慢,成为 LATCH 的长期持有者。解决:排查时把“谁在周期性访问表空间元数据”纳入怀疑范围,必要时调整监控采集频率或范围,减少对超大对象的频繁快照。
6. 设计取舍:为什么“空间大”反而成了性能负债
这套机制背后其实藏着一个不太直观的设计取舍。临时表空间按需增长,本意是让突发的大排序、大临时表不至于失败,属于“用空间换成功率”的保守设计;遗留的临时数据文件不主动删除,也是为了不在正常路径上引入额外的清理开销。代价就是:一旦某个瞬间并发极高、大量语句同时用临时表,空间被撑大之后不会自己缩回去,而表空间元数据的遍历成本是随规模增长的。于是“容量上的安全垫”变成了“元数据操作上的负债”,再通过一把保护内部数据结构的 LATCH,把单点变慢放大成全局排队。
要验证这条链路,最直接的办法是做一次受控实验:用跟踪工具在特定函数入口挂起实例,让某个操作停在“获取容器页”这一步,然后观察其他会话是否卡在创建临时表上。跟踪工具可以按函数入口设置挂起条件,实例被“暂停”后,正好从容收集现场信息,再恢复运行。这种做法的价值不是复现故障,而是把“猜测的因果”变成“可观察的因果”——你能亲眼看到持有者停在哪、等待者堵在哪。
| 观察点 | 正常表现 | 异常表现 | 指向 |
|---|---|---|---|
| 活动会话数 | 个位数到二三十 | 频繁突破 50 | SQL 执行变长 |
| 等待时间占比 | 读/锁/排序为主 | 非读非锁非排序占 95% | LATCH 争用 |
| LATCH 采样 | 无集中等待 | 一持有者多等待者 | 内部结构争用 |
| 临时表空间大小 | 很小 | 异常膨胀到 GB 级 | 元数据操作变慢 |
| 表空间列表命令 | 秒级返回 | 数秒才返回 | 快照路径被拖慢 |
从那以后我每次接手一个“指标全绿但就是慢”的库,都会强制走一遍“活动会话状态 → 等待时间分布 → LATCH 重复采样 → 临时表空间规模”这条链路,而不是先动 SQL。因为性能问题里最贵的不是修复,是方向错了还自信地走下去。希望帮到你。
本文还有配套的精品资源,点击获取