关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
在当今数据驱动的时代,数据库是任何应用系统的核心。而慢SQL
,则是数据库最怕又最常见的问题。它悄然滋生,初期难以察觉,但一旦爆发,便会导致应用响应迟缓、系统资源耗尽,甚至引发服务雪崩。
因此,一个设计良好的慢SQL
报警系统,不再是可选项,而是保障系统稳定性和用户体验的生命线。
02 契机
前两天帮同事排查一个问题,线下都是好好的,一到生产环境,代码卡死,最后通过Arthas
工具才发现,是因为慢SQL
导致的,耗时大概1分钟左右。真的是吃了大亏了。

但是,当时的大坑就是因为慢SQL
导致客户端超时超时,拿到的数据结果为空,从而报空指针异常,被空指针直接误导带偏。
Arthas
虽然可以采集结果,但也只是全部执行完成之后才会打印信息。慢SQL
会直接将信息阻塞,给人的错觉就是没有执行到监控的地方。
于是想,如果SQL
执行完执行时间超过某个阈值,自动推送消息,就可以快速定位到问题了。带着这个问题,我们开启今天的文章介绍。
03 Mysql自带的参数
Mysql
本身支持慢SQL
的监控,会将超过阈值的SQL
保存到执行的位置。关键参数如下:
slow_query_log
:开启慢SQL
日志的开关(ON/OFF)slow_query_log_file
:慢SQL
存放的位置long_query_time
:阈值,单位秒(s)
3.1 设置命令
这些参数可以在Mysql
的配置文件里面修改,也可以通过命令修改。我们先通过命令查看:
sh
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'slow_query_log_file';
SHOW VARIABLES LIKE 'long_query_time';

3.2 监控文件
我们通过SHOW VARIABLES LIKE 'slow_query_log_file'
找到慢SQL
的位置,通过命令可以追踪日志:
sh
tail -f /data/log/slow.log

当有慢SQL
超过阈值会自动将信息写入文件。
3.3 日志采集
文件监控到了,但是并不能主动报警,我们需要采集日志数据然后分析报警。日志的采集工具有很多如:Filebeat
、LogStash
、Floume
等。
关于日志采集我们会后期会专门用一期讲,这里就不在赘述!
04 Mybaits拦截器监控
Mybaits
拦截器不仅能够打印SQL
,当然还可以监听SQL
执行的时间。这个需要我们自己去实现,灵活度更好,不需要任何第三方的插件。
4.1 拦截器案例
java
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class})
})
@Component
public class SqlExcuteTimeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StopWatch watch = new StopWatch("SqlExcuteTimeInterceptor");
watch.start();
Object proceed = invocation.proceed();
watch.stop();
// 打印SQL
StatementHandler handler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = handler.getBoundSql();
// 获取原始SQL
String sql = boundSql.getSql();
Object param = boundSql.getParameterObject();
// 美化SQL输出
System.out.println("\n=============== SQL日志 ===============");
System.out.println("原始SQL:" + sql);
System.out.println("SQL: " + sql.replaceAll("\\s+", " ").trim());
System.out.println("参数: " + JSON.toJSONString(param));
System.out.println("执行SQL耗时: " + watch.getTotalTimeMillis() + "ms");
System.out.println("=========================================");
return proceed;
}
}
我们的拦截器中进行了执行时间的计算以及SQL
的打印。要注意的是,我们的拦截器针对query
和update
方法进行了拦截。
4.2 实现效果

这里的效果只是将结果打印出来。实际应用中,需要根据执行的时间和配置阈值校验,最后推送给负责人。可以通过企业微信、钉钉、微信、手机短信等工具。
05 小结
其实很多三方工具(如SkyWalking
等)已经集成了SQL
的报警,尤其云厂商。只需要配置对应的报警方式即可。但是针对一些小微企业,类似拦截器这样的实现更能满足个性的话需求,最重要的节省成本。
而我们要做的就是设计好慢SQL
的报警,要设计一个慢SQL
报警系统,本质上是在构建一个"数据库性能风险的早期预警系统"。它要求我们不仅是技术的堆砌,更是对数据库性能管理的深刻理解。
从一个简单的日志收集器,到一个具备智能分析、精准报警和闭环治理能力的平台,每一步进化都将为业务的稳定和高效运行注入更强的韧性。投资这样一个系统,就是投资系统的未来。