4. 数据库监控(上):Oracle/MySQL关键性能指标、慢查询监控、连接池监控

数据库监控,说白了就是给ERP系统的心脏做体检。我做了这么多年运维,见过太多因为数据库问题导致整个业务瘫痪的案例。有一次,一个客户的ERP系统在月底结算时突然卡死,最后发现是连接池爆了。嗯,从那以后,我对数据库监控就格外上心。

今天咱们先聊上半部分,重点讲三个核心模块:关键性能指标、慢查询监控、连接池监控。这些都是日常运维中必须盯紧的。

4.1 关键性能指标(KPI)

我个人习惯,先把数据库的KPI分成两类:资源类效率类。资源类告诉你数据库吃不吃力,效率类告诉你数据库干不干活。

4.1.1 Oracle关键指标

指标类别 指标名称 正常范围 告警阈值
资源类 CPU使用率 < 70% > 85% 持续5分钟
资源类 内存使用率(SGA+PGA) < 80% > 90%
资源类 磁盘IO等待时间 < 10ms > 20ms
效率类 每秒事务数(TPS) 根据业务基线 下降超过30%
效率类 缓冲区命中率 > 99% < 95%
效率类 硬解析率 < 1% > 5%

这里我特别想强调一下硬解析率。Oracle的SQL执行流程中,硬解析是非常消耗CPU的操作。我在项目中遇到过,一个ERP模块上线后,数据库CPU直接飙到100%。查了半天,发现是代码里拼接SQL导致大量硬解析。后来改成绑定变量,CPU直接降到20%。

Oracle监控脚本示例(检查硬解析率):

SELECT 
  ROUND(100 * (1 - (SUM(EXECUTIONS) / SUM(PARSE_COUNT))), 2) AS hard_parse_ratio
FROM V$SQLAREA
WHERE PARSE_COUNT > 0;

4.1.2 MySQL关键指标

MySQL的监控思路和Oracle类似,但指标名称和关注点略有不同。你想想看,MySQL的InnoDB引擎和Oracle的架构差异还是挺大的。

指标类别 指标名称 正常范围 告警阈值
资源类 QPS(每秒查询数) 根据业务基线 超过基线50%
资源类 InnoDB缓冲池命中率 > 99% < 95%
资源类 临时表创建率 < 10次/秒 > 50次/秒
效率类 慢查询数量 < 5次/分钟 > 20次/分钟
效率类 锁等待次数 < 1次/秒 > 5次/秒

我的经验:MySQL的临时表创建率是个容易被忽略的指标。如果这个值突然升高,通常意味着SQL没有走索引,或者排序操作过多。我曾经排查过一个案例,就是临时表创建率从5飙到200,最后发现是一个报表查询没有加limit。

4.2 慢查询监控

慢查询,是数据库性能问题的头号杀手。说白了,就是SQL执行得太慢,拖累了整个系统。我见过最夸张的一次,一个慢查询跑了8分钟,直接把ERP的订单录入功能给堵死了。

4.2.1 Oracle慢查询监控

Oracle的慢查询监控,我主要用两个视图:V$SQLDBA_HIST_SQLSTAT。前者看实时,后者看历史。

实时监控慢查询:

SELECT 
  SQL_ID,
  ROUND(ELAPSED_TIME / 1000000, 2) AS elapsed_seconds,
  EXECUTIONS,
  ROUND(ELAPSED_TIME / DECODE(EXECUTIONS, 0, 1, EXECUTIONS) / 1000000, 2) AS avg_time,
  SQL_TEXT
FROM V$SQL
WHERE ELAPSED_TIME / DECODE(EXECUTIONS, 0, 1, EXECUTIONS) > 1000000
ORDER BY avg_time DESC
FETCH FIRST 10 ROWS ONLY;

这个查询会找出平均执行时间超过1秒的SQL。我个人习惯把阈值设成500毫秒,因为ERP系统对响应时间要求比较高。

注意:Oracle的 V$SQL 视图在实例重启后会清空。如果你需要长期监控,建议用 DBA_HIST_SQLSTAT 历史视图。我曾经吃过这个亏,重启后查不到历史数据,排查问题费了好大劲。

4.2.2 MySQL慢查询监控

MySQL的慢查询监控相对简单。首先,确保开启了慢查询日志:

-- 查看当前配置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';

-- 开启慢查询日志(生产环境建议开启)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过1秒的记录
SET GLOBAL log_queries_not_using_indexes = ON;

然后,用 mysqldumpslow 工具分析日志:

# 按平均查询时间排序,显示前10条
mysqldumpslow -t 10 -s at /var/log/mysql/slow.log

# 按执行次数排序
mysqldumpslow -t 10 -s c /var/log/mysql/slow.log

嗯,这里要注意。慢查询日志如果一直开着,文件会变得很大。我建议设置一个合理的轮转策略,比如每天切割一次,保留7天。

4.3 连接池监控

连接池,是ERP系统最容易出问题的地方之一。你想想看,ERP系统通常有成百上千个并发用户,如果每个请求都新建一个数据库连接,数据库根本扛不住。连接池的作用就是复用连接,但一旦配置不当,就会出大问题。

4.3.1 连接池的核心指标

指标 说明 正常范围 告警阈值
活跃连接数 当前正在执行SQL的连接数 < 最大连接数的80% > 90%
空闲连接数 空闲等待的连接数 最大连接数的10%-20% < 5% 或 > 50%
等待连接数 等待获取连接的请求数 0 > 0 持续10秒
连接超时次数 获取连接超时的次数 0 > 0

我的经验:等待连接数这个指标,一旦大于0,就意味着系统已经出现瓶颈了。我曾经处理过一个案例,ERP系统每天早上9点准时卡顿,查了监控发现等待连接数在8:55开始飙升,到9:05达到峰值。最后发现是定时任务和用户登录高峰撞在一起了。解决方案很简单,把定时任务推迟到10点执行。

4.3.2 Oracle连接池监控

Oracle的连接池监控,我通常看 V$SESSIONV$RESOURCE_LIMIT

-- 查看当前会话状态
SELECT 
  COUNT(*) AS total_connections,
  SUM(CASE WHEN STATUS = 'ACTIVE' THEN 1 ELSE 0 END) AS active_connections,
  SUM(CASE WHEN STATUS = 'INACTIVE' THEN 1 ELSE 0 END) AS idle_connections
FROM V$SESSION;

-- 查看连接数限制
SELECT 
  RESOURCE_NAME,
  CURRENT_UTILIZATION,
  MAX_UTILIZATION,
  LIMIT_VALUE
FROM V$RESOURCE_LIMIT
WHERE RESOURCE_NAME IN ('sessions', 'processes');

4.3.3 MySQL连接池监控

MySQL的连接池监控相对简单,主要看 SHOW STATUSSHOW VARIABLES

-- 查看当前连接状态
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
SHOW STATUS LIKE 'Threads_cached';
SHOW STATUS LIKE 'Connections';

-- 查看最大连接数配置
SHOW VARIABLES LIKE 'max_connections';

-- 查看连接超时配置
SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';

避坑指南:我曾经遇到过一个问题,MySQL的 wait_timeout 设置得太长(默认8小时),导致大量空闲连接占着连接池不放。后来我把 wait_timeout 改成300秒(5分钟),连接池的压力一下子就降下来了。但要注意,如果应用层有长连接需求,这个值不能设得太短,否则会频繁断开重连。

4.4 总结与建议

好了,今天的内容就到这里。我总结几个要点:

  • 关键指标要盯紧:资源类指标看CPU、内存、IO;效率类指标看TPS、命中率、解析率。
  • 慢查询是头号敌人:Oracle用 V$SQLDBA_HIST_SQLSTAT,MySQL用慢查询日志 + mysqldumpslow
  • 连接池要防爆:重点关注等待连接数和连接超时次数,这两个指标一旦大于0,就要立刻排查。

下一节,我们会继续聊数据库监控的下半部分:表空间监控、锁监控、以及备份监控。这些都是实战中经常用到的技能,到时候我会分享更多踩坑经验。

记住一句话:数据库监控不是为了看数据,而是为了在问题发生前就发现它。嗯,这才是监控的真正价值。