
简介这份文档面向DB2数据库运维DBA与性能调优学习者取材于某银行DB2系统的一次真实故障业务响应变慢、活动会话数异常攀升常规排查CPU、内存、I/O与锁等待均无收获最终锁定系统临时表空间TEMPSPACE1膨胀至10GB这一根因。文中完整还原了从db2top观察ACTIVE SESSION、LATCH等待分析、STACK堆栈收集到用db2trc暂停实例抓取现场的诊断链路并给出SQL优化、参数调整与临时空间清理等解决思路对排查同类性能问题有直接参考价值。资源包共1个doc文件约607KB为可离线查阅的案例文档。目前已有5903人学习下载适合希望积累真实故障定位经验、补充DB2性能分析工具用法的读者研读。1. 一次“什么都正常”的性能雪崩从 ACTIVE SESSION 飙升到 TEMPSPACE1 的 10G业务侧反馈系统变慢监控里 ACTIVE SESSION 从平时个位数频繁冲到 50 以上登录服务器一看多条 SQL 执行时间从毫秒级涨到 3~6 秒。CPU 正常、内存正常、I/O 正常、缓冲池命中率正常、没有 LOCK WAIT执行计划翻来覆去看不出毛病——这是很多 DBA 都遇到过的“玄学”现场。这份文档记录的就是这样一个案例常规排查全部走完没有结论最后把矛头指向了一个几乎没人关心的对象——DB2 系统临时表空间 TEMPSPACE1它已经涨到了 10G。适合正在做 DB2 运维、被慢 SQL 和 LATCH 等待折磨的从业者也适合想补齐“非典型性能问题”排查思路的读者。2. 先把常规指标排干净db2top 与动态 SQL 抓取的正确姿势2.1 ACTIVE SESSION 高先分清是“忙”还是“卡”ACTIVE SESSION 是 DB2 监控里最直观的指标之一用db2top -d dbname进去按d就能看到实时曲线默认 2 秒刷新一次。但光看数字没用得看会话处于什么状态按l进入 SESSIONS 页面如果大量会话是 UOW Executing说明语句真的在跑如果是 Lock Waiting那是锁的问题如果是 Queued要怀疑 WLM 并发限制。这个案例里活动会话全是 UOW Executing且业务方确认访问量没有增长基本可以判定是数据库侧性能退化而不是业务洪峰。这里有个容易被忽略的细节UOW Waiting 状态的会话不计入 ACTIVE SESSION因为它处于两条语句之间的空档。所以看到 ActSess 高先别急着扩容先确认状态分布否则很容易把“语句变慢”误判成“并发变高”。2.2 用 MON_CURRENT_SQL 抓“正在跑”的语句确认是性能问题后第一步是抓现行。MON_CURRENT_SQL管理视图能同时看到动态 SQL 和静态 SQL按已运行时间倒序排直接锁定嫌疑对象SELECT COORD_MEMBER AS MEMBER, VARCHAR(SESSION_AUTH_ID,10) AS USER, VARCHAR(CLIENT_APPLNAME,10) AS APPNAME, ELAPSED_TIME_SEC AS ELAPSEDTIME, VARCHAR(ACTIVITY_STATE,10) AS STATE, TOTAL_CPU_TIME, ROWS_READ, ROWS_RETURNED, QUERY_COST_ESTIMATE, DIRECT_READS, DIRECT_WRITES, VARCHAR(STMT_TEXT,2000) AS STMT_TEXT FROM SYSIBMADM.MON_CURRENT_SQL ORDER BY ELAPSED_TIME_SEC DESC;ELAPSED_TIME_SEC是语句已运行秒数ACTIVITY_STATE能区分是执行中还是等待中DIRECT_READS/DIRECT_WRITES偏大往往意味着走了临时表空间或直接 I/O。注意这个视图抓的是“快照”语句没跑完时 ELAPSED TIME 会比真实执行时间短所以要在 ACTIVE SESSION 高的时候多抓几次别抓一次就下结论。2.3 MON_GET_PKG_CACHE_STMT把执行时间拆开看抓到慢语句后关键是搞清楚时间花在哪。MON_GET_PKG_CACHE_STMT表函数能返回等待时间、锁等待、排序时间等细分项下面这条查询把各项等待占比算出来比裸看原始字段直观得多SELECT MEMBER, NUM_EXECUTIONS, STMT_EXEC_TIME, DECIMAL((TOTAL_ACT_WAIT_TIME / DOUBLE(STMT_EXEC_TIME)) * 100, 5, 2) AS pct_wait, DECIMAL((POOL_READ_TIME / DOUBLE(STMT_EXEC_TIME)) * 100, 5, 2) AS pct_read, DECIMAL((LOCK_WAIT_TIME / DOUBLE(STMT_EXEC_TIME)) * 100, 5, 2) AS pct_lock, DECIMAL((LOG_DISK_WAIT_TIME / DOUBLE(STMT_EXEC_TIME)) * 100, 5, 2) AS pct_log, DECIMAL((TOTAL_SECTION_SORT_TIME / DOUBLE(STMT_EXEC_TIME)) * 100, 5, 2) AS pct_sort, CAST(FLOAT(STMT_EXEC_TIME) / FLOAT(NUM_EXECUTIONS) AS DECIMAL(10,3)) AS AVG_EXEC_TIME, VARCHAR(STMT_TEXT,500) AS STMT_TEXT FROM TABLE(MON_GET_PKG_CACHE_STMT(NULL, NULL, NULL, -2)) WHERE NUM_EXECUTIONS 1 AND STMT_EXEC_TIME 0;参数-2表示取所有成员上的语句NUM_EXECUTIONS 1过滤掉只跑过一次的语句避免平均值失真。这个案例里跑出来 5 条 with 开头的语句PCT_WAIT超过 95%但等待项里 READ、Lock、日志、排序都不高——说明它们在等一个“别的东西”。这时候再加TOTAL_EXTENDED_LATCH_WAIT_TIME字段答案就浮出来了等的是 LATCH。提示如果应用是拼 SQL 而不是变量绑定PACKAGE CACHE 里几乎每条语句都是“新语句”NUM_EXECUTIONS 普遍很小统计意义会打折要结合 MON_CURRENT_SQL 交叉验证。3. LATCH 等待定位db2pd 抓现场与 STACK 黑匣子解读3.1 db2pd -latches -rep 2短窗口抓不到就拉长LATCH 是 DB2 内部为保证多线程访问共享内存结构一致性而设的轻量锁文档里几乎没有面向用户的说明所以看到pool_table_latch这种名字基本等于看天书。第一次用db2pd -latches没发现异常很正常因为这个案例里的 LATCH 等待是间歇性的几秒就散。改成持续采样db2pd -latches -rep 2-rep 2表示每 2 秒输出一次并持续刷新。这次抓到了一个 EDU 持有pool_table_latch另外 23 个 EDU 在排队等它。23 个等待者意味着 ACTIVE SESSION 至少 24和监控曲线完全对得上。到这一步可以确认慢 SQL 只是表象真正的瓶颈是 LATCH 争用。3.2 db2pd -stack把 Holder 和 Waiter 的调用栈留下来LATCH 几秒就释放等你想去看 Holder 在干嘛现场已经没了。db2pd的 stack 收集功能在抓调用栈的同时会把每个 EDU 当时的 LATCH 信息一起带出来等于给现场拍了一张带注释的照片cd /tmp mkdir stack0531 db2pd -stack all dumpdir/tmp/stack0531 -rep 3 10dumpdir指定输出目录不指定就落到 DIAGPATH-rep 3 10是每 3 秒抓一次、连抓 10 次因为间歇性问题一次大概率抓空。抓完先 grep 一下有没有目标 LATCHcd /tmp/stack0531 grep pool_table_latch *stack.txt输出里会区分Holding Latch type和Waiting on latch type前者是 Holder后者是 Waiter还带 Address、Line、File 信息。同一个 Address 的 Holder 和 Waiter 就是一对顺着文件号就能把两边的栈对上。注意生产库繁忙时段收集 stack 会明显吃资源可能进一步拖慢数据库务必挑影响可控的窗口抓够次数就停别挂着-rep跑一晚上。3.3 读栈技巧从函数名猜操作类型栈里全是_Z...开头的 C mangled 符号看着劝退但函数名本身信息量很大。Holder 栈里出现sqlbSnapshotTablespace - sqlbMonSMSGetContainerPages字面意思就是对表空间做快照、在监控 SMS 表空间时取容器页数Waiter 栈里是sqldTableCreateTemp - sqldInternalCreateTable - sqlbGetSysTempDatapool明显是在创建内部临时表、使用系统临时表空间再结合sqldEvalDataPred谓词求值可以判断这是一条带临时表的查询在等 LATCH。结论链条就此闭合监控代理定期对表空间做快照快照操作持有pool_table_latch时间过长阻塞了正在创建临时表的查询。而快照为什么慢往下查表空间db2 LIST TABLESPACES SHOW DETAIL本身都要跑好几秒TEMPSPACE1 显示 354661 个页、页大小 32768 字节算下来正好约 10G容器目录里躺着一堆SQL043xx.MEMBER0000.TDA文件。3.4 analyzestack把几十个 stack 文件汇总成结论手工 grep 几十个文件效率太低DB2 安装目录sqllib/pd下有个 Perl 脚本analyzestack能把相同栈归并统计并做 LATCH 分析perl ~/sqllib/pd/analyzestack -d 50 -i /tmp/stack0531 -l-d 50是比对栈时比较的函数层数层数越大归并越严格-i指定 stack 文件目录也可以直接列多个文件-l开启 LATCH 分析。跑完生成LatchAnalysis.out和StackAnalysis.out两个文件Holder/Waiter 配对和热点栈一目了然。这个脚本是 as-is 提供的示例工具没有官方支持但做批量归并确实省事建议在测试环境先跑通再上生产。4. 避坑与排查这类问题最容易翻车的五个地方现象一常规指标全绿就以为不是数据库问题。原因CPU、内存、I/O、缓冲池命中率这些指标反映的是资源层LATCH 争用属于内部并发控制层资源层完全可能风平浪静。解决ACTIVE SESSION 异常且业务量未增长时把db2pd -latches -rep和MON_GET_PKG_CACHE_STMT的 LATCH 等待字段纳入必查项别在资源指标上反复打转。现象二看到慢 SQL 就直接改 SQL、加索引。原因案例里确实有几条全表扫描的语句加索引后局部变快但整体没好转——因为根因是 LATCHSQL 优化只是治标。解决先用PCT_WAIT判断时间到底花在等待还是执行上等待占比高的语句优化 SQL 文本收益有限要往等待对象上查。现象三db2pd -latches跑一次没异常就排除 LATCH。原因间歇性 LATCH 等待窗口只有几秒单次采样命中率极低。解决用-rep持续采样配合-stack连抓多次抓不到就换时段再来别用一次结果下结论。现象四发现临时表空间大直接重启实例。原因SMS 临时表空间里遗留的 TDA 文件在实例重启后并不会释放这是文档里明确的工作机制。解决必须对数据库做 deactivate/activate才能让这些容器文件被回收重启实例属于无效操作白折腾一次维护窗口。现象五清理完就收工不追根因。原因TDA 文件堆积往往对应某个瞬间的并发尖峰案例里是 ACTIVE SESSION 一度冲到 800 多不查清触发点同样的事还会再来一次。解决对照监控历史曲线定位暴涨时间点确认当时的批量任务或异常并发从应用侧做限流或错峰。5. 用 db2trc 做一次“暂停”实验验证 pool_table_latch 的持有路径问题解决后作者没有停在“好了就行”而是用db2trc做了一次小实验反向验证“表空间快照操作持有 pool_table_latch”这个判断。db2trc除了抓函数调用流还能在命中指定函数入口时挂起实例给你从容取现场的机会。实验思路是在第一个窗口连库并开启带挂起条件的 trace在第二个窗口触发LIST TABLESPACES SHOW DETAIL让实例在sqlbSMSGetContainerPages入口处停住此时再去查 LATCH 状态就能确认这条路径确实持有目标 LATCH。# 窗口一连接数据库并开启 trace命中指定函数入口时挂起 db2 CONNECT TO mydb db2trc on -crash DB2.SQLB.sqlbSMSGetContainerPages.entry -suspend # 窗口二触发一次表空间详情查询 db2 LIST TABLESPACES SHOW DETAIL # 回到窗口一此时实例已挂起另开窗口查 LATCH 与栈 db2pd -latches db2pd -stack all dumpdir/tmp/trc_stack # 恢复并关闭 trace db2trc off db2trc dmp /tmp/trc_dump.bin db2trc fmt /tmp/trc_dump.bin /tmp/trc_fmt.txt-crash后跟的是挂起条件格式为组件.函数.entry命中即 suspenddb2trc dmp导出二进制流fmt转成可读文本。这个手法在排查 HANG 类问题时同样好用——与其反复采样碰运气不如让实例在关键路径上“定格”把 Holder 和 Waiter 一次看全。需要提醒的是挂起实例期间业务全部停摆只能在测试库或维护窗口做生产上直接玩这个属于给自己找事故。从那以后我每次遇到“指标全绿但会话数异常”的 DB2 现场都会强制走一遍固定顺序先看 ACTIVE SESSION 状态分布再拉MON_GET_PKG_CACHE_STMT的等待占比等待项说不清就上db2pd -latches -rep加-stack连抓最后顺手看一眼 TEMPSPACE1 的实际大小和容器目录。这套顺序不花哨但能避免在错误的方向上加班。希望帮到你。本文还有配套的精品资源点击获取