DB2的快照监视器(Snapshot Monitor)是数据库自带的诊断利器。它可以在任意时刻对数据库内部状态拍一张快照,把当时的锁信息、SQL执行情况、缓冲池命中率、排序活动等数据完整记录下来。相比第三方监控工具,快照监视器零成本、开箱即用,特别适合排查突发性能问题。本文将从快照监视器的开关配置、常用监控维度、SQL实践和数据分析四个方面,完整讲解SNAPSHOT的使用方法。

一、快照监视器的工作原理与前置配置
快照监视器的核心思想是计数器采集。DB2在数据库引擎内部维护了一组监视器开关(Monitor Switches),每个开关对应一类数据采集项,比如语句级统计、表级统计、锁信息、排序信息等。开关打开后,引擎在日常运行中持续累计这些计数器,当你执行快照命令或查询快照表函数时,DB2就把当前累计值输出给你。
默认情况下,大部分监视器开关是关闭的,因为开启会带来轻微的性能开销。使用快照前必须先确认开关状态,可以用下面的命令查看:
db2 get monitor switches
输出中每一行代表一个开关,例如DFT_MON_STMT(语句)、DFT_MON_LOCK(锁)、DFT_MON_BUFPOOL(缓冲池)、DFT_MON_SORT(排序)、DFT_MON_TABLE(表)。状态为OFF的需要打开:
-- 在实例级别打开常用开关 db2 update dbm cfg using DFT_MON_LOCK on db2 update dbm cfg using DFT_MON_STMT on db2 update dbm cfg using DFT_MON_BUFPOOL on db2 update dbm cfg using DFT_MON_SORT on db2 update dbm cfg using DFT_MON_TABLE on
如果只是临时排查问题,也可以在会话级别打开,避免影响整个实例:
-- 会话级开关,仅当前连接有效 db2 update monitor switches using lock on statement on sort on
配置完成后再次执行get monitor switches确认生效。需要提醒的是,语句级监控(STATEMENT开关)在高并发系统上开销相对明显,建议排查期间临时打开,排查完及时关闭,通过重置监视器开关即可清空累计数据:
db2 reset monitor all
二、获取快照的两种主要方式
获取快照有传统命令行和SQL表函数两条路径。命令行方式通过GET SNAPSHOT命令直接输出,适合快速人工查看:
-- 查看数据库级别快照 db2 get snapshot for database on sample -- 查看所有锁信息 db2 get snapshot for locks on sample -- 查看动态SQL执行统计 db2 get snapshot for dynamic sql on sample -- 查看所有应用连接状态 db2 get snapshot for applications on sample
第二种方式是SQL接口,通过快照表函数把监控数据当成普通表来查询,便于过滤、排序和定时采集。常用的表函数包括SNAPSHOT_DATABASE、SNAPSHOT_LOCKWAIT、SNAPSHOT_DYN_SQL、SNAPSHOT_APPL_INFO等,下面这个查询可以直接找出当前正在发生锁等待的会话:
SELECT SUBSTR(APPLICATION_HANDLE,1,6) AS APP_HANDLE,
AGENT_ID,
LOCK_WAIT_START_TIME,
LOCK_NAME,
LOCK_OBJECT_TYPE
FROM TABLE(SYSPROC.SNAPSHOT_LOCKWAIT('',-1)) AS T
ORDER BY LOCK_WAIT_START_TIME;
两种方式各有优势。命令行输出信息全面、无需写SQL,适合现场应急;表函数方式灵活可编程,可以配合脚本每隔几秒采集一次写入历史表,形成趋势分析数据。实际运维中通常两者结合:先用命令行快速确认现象,再用SQL方式做持续采集和深入分析。
三、关键监控指标与SQL级性能分析
拿到快照后,最重要的是看懂关键指标。数据库级快照中,缓冲池命中率(Buffer Pool Hit Ratio)是第一优先级,它反映数据读取是否主要依赖内存。计算公式为:1 - (缓冲池物理读 / 缓冲池逻辑读)。命中率长期低于95%通常意味着内存不足或存在全表扫描,需要重点关注。相关字段在快照输出中的示例如下:
SELECT BP_NAME,
TOTAL_LOGICAL_READS,
TOTAL_PHYSICAL_READS,
DECIMAL(1 - (DOUBLE(TOTAL_PHYSICAL_READS) /
NULLIF(TOTAL_LOGICAL_READS,0)),5,4) AS HIT_RATIO
FROM TABLE(SYSPROC.SNAPSHOT_BP('',-1)) AS T;
第二个重点指标是排序溢出(Sort Overflows)。如果排序总次数中溢出到磁盘的比例偏高,说明SORTHEAP配置不足,大量临时表空间IO会拖慢查询。第三个是死锁和锁升级次数,Deadlocks和Lock Escalations不为零时需要检查事务粒度和LOCKLIST、MAXLOCK参数。
对于SQL级分析,动态SQL快照最有价值。它会列出每条SQL语句自开关打开以来的执行次数、累计CPU时间、总执行时间、行读取数等。通过计算平均执行时间排序,可以快速锁定最耗资源的语句:
SELECT SUBSTR(STMT_TEXT,1,60) AS SQL_TEXT,
NUM_EXECUTIONS AS EXEC_CNT,
DECIMAL(DOUBLE(TOTAL_EXEC_TIME) /
NULLIF(NUM_EXECUTIONS,0),10,6) AS AVG_EXEC_TIME_S,
ROWS_READ / NUM_EXECUTIONS AS AVG_ROWS_READ
FROM TABLE(SYSPROC.SNAPSHOT_DYN_SQL('SAMPLE',-1)) AS T
WHERE NUM_EXECUTIONS > 0
ORDER BY AVG_EXEC_TIME_S DESC
FETCH FIRST 10 ROWS ONLY;
重点关注两类语句:一是平均行读取数远大于返回行数的语句,这类通常缺少索引;二是执行次数多且单次耗时高的语句,优化它们收益最大。找到目标后,可以用db2expln或db2advis进一步查看执行计划和索引建议。
四、搭建周期性监控与注意事项
单次快照只能反映瞬时状态,生产环境更需要周期性采集。常见做法是编写一个shell脚本,结合db2 reset monitor实现增量统计:每小时先保存快照结果到带时间戳的文件,再重置计数器,这样每份数据都精确对应一个时间段的增量,不会因为累计值过大而掩盖突发问题。
#!/bin/bash
TS=$(date +%Y%m%d_%H%M%S)
db2 connect to sample
db2 "SELECT * FROM TABLE(SYSPROC.SNAPSHOT_DYN_SQL('SAMPLE',-1))" \
> /db2mon/dynsql_$TS.log
db2 "SELECT * FROM TABLE(SYSPROC.SNAPSHOT_LOCKWAIT('',-1))" \
> /db2mon/lockwait_$TS.log
db2 reset monitor for database sample
db2 connect reset
使用快照监视器还有几点注意事项。第一,快照数据是实例内存中的累计值,实例重启后清零,不要把快照数据当成长期统计报表使用,长期趋势分析建议启用DB2本身的监控数据压缩归档功能。第二,如果数据库启用了工作负载管理(WLM),部分活动数据会转移到WLM的监控体系中,快照看到的可能不完整,可以配合MON_GET_AGENT等管理视图交叉验证。第三,监控语句开关时要评估存储和性能开销,高TPS系统中长时间开启语句级监控可能占用数GB内存。
总体来说,DB2快照监视器是一个轻量但功能完备的实时诊断工具。掌握开关配置、表函数查询和关键指标解读这三项技能后,绝大多数性能问题——无论是锁等待、慢SQL还是内存瓶颈——都能在没有第三方工具的情况下快速定位。建议在日常运维中把快照采集脚本固化下来,形成数据库的健康巡检基线,问题发生时就能有据可查。