SQL监控应聚焦query_duration(P95/P99)、slow_queries、connection_count和lock_wait_time四大核心指标,结合执行计划、上下文链路与业务标签精准定位问题。

SQL 监控不是看越多指标越好,而是盯住几个能直接反映查询健康度和数据库压力的核心项——query_duration、slow_queries、connection_count 和 lock_wait_time 足够定位 80% 的线上问题。
查得慢?先盯 query_duration 的 P95 和 P99
平均耗时(P50)容易掩盖长尾问题,真实卡顿往往藏在 P95 之后。比如一个接口平均 20ms,但 P99 达到 1.2s,说明有少量查询严重拖累体验。
- 监控必须区分读写:
SELECT和UPDATE/INSERT的耗时分布通常差异很大,混在一起会失真 - 按 schema 或业务模块打标:同一 DB 下,
orders表的慢查询比logs表更需优先处理 - 避免只采样:某些 APM 工具默认只抓取 1% 的慢查询,漏掉偶发但关键的超时语句
slow_queries 数量突增,大概率是执行计划崩了
MySQL 的 slow_queries 计数器每秒跳一次,比单看耗时更敏感。它不依赖阈值设置(如 long_query_time=1),而是由实际执行路径决定——比如某次 JOIN 突然走全表扫描,哪怕只多花 300ms,也会被计入。
- 配合
EXPLAIN日志一起看:光知道“变慢了”没用,要确认是否走了索引、是否出现Using temporary或Using filesort - 注意时间窗口对齐:Prometheus 抓取间隔设为 15s,但慢查询日志落盘可能有秒级延迟,导致计数和日志无法精确匹配
- 不要忽略
pt-query-digest的Query_time分布直方图,它比单一数值更能暴露毛刺规律
connection_count 持续高位,别急着加连接池
连接数高 ≠ 连接池配置小,更可能是应用端未正确释放连接,或数据库端因锁、事务阻塞导致连接 hang 住。
- 对比
Threads_running(真正活跃线程)和Threads_connected:如果后者远大于前者,说明大量连接空闲但未断开 - 检查
wait_timeout和interactive_timeout是否远高于应用实际心跳周期,导致连接堆积 - Java 应用常见陷阱:
HikariCP的maxLifetime设为 0,连接永不过期,配合 MySQL 的wait_timeout=28800,可能引发连接复用错乱
lock_wait_time 上升,说明事务冲突正在恶化
PostgreSQL 的 pg_locks 视图中 granted = false 的等待行数,或 MySQL 的 Innodb_row_lock_waits,都是比 CPU 更早预警死锁和热点行竞争的信号。
- 重点看等待时长中位数而非总数:100 次 1ms 等待不如 1 次 500ms 等待危险
- 关联
information_schema.INNODB_TRX查当前持有锁的事务,确认是否长事务拖住整个表 - 注意隔离级别影响:READ-COMMITTED 下的间隙锁范围比 REPEATABLE-READ 小,但某些 ORM 自动生成的
SELECT ... FOR UPDATE仍可能锁整范围
真正难的不是采集这些指标,而是把它们和具体 SQL、事务上下文、应用调用链串起来。比如 lock_wait_time 升高时,如果不能立刻定位到是哪个微服务的哪个 API 在持有一个 30 秒未提交的事务,指标就只是摆设。










