SQL应用慢查询是数据库性能问题中最高频的场景之一,长期存在的慢查询会导致接口响应变慢、数据库连接池耗尽甚至引发系统雪崩。仅依靠单一的监控手段很难全面覆盖慢查询的发现、定位和优化全流程,将APM(应用性能监控)与日志分析结合,能够形成从请求入口到数据库执行的完整链路追踪能力。

一、慢查询监控的核心诉求
有效的SQL慢查询监控需要满足以下几个核心目标:
- 能够及时发现执行耗时超过阈值的SQL语句,避免问题扩大
- 可以关联到具体的业务请求、调用链路和用户信息,快速定位触发场景
- 能够保存SQL执行的全量上下文信息,包括参数、执行计划、返回行数等,支撑优化分析
- 支持历史趋势查询,能够识别慢查询的周期性变化或者新增慢查询
二、APM在慢查询监控中的能力
APM工具通过在应用端植入探针,能够无侵入地采集应用运行时的各类性能数据,针对SQL慢查询监控有以下天然优势:
1. 链路关联能力
APM可以自动将一次业务请求经过的所有服务节点、数据库调用串联起来,当发现慢SQL时,可以直接追溯到是哪个接口的哪次请求触发的,甚至关联到对应的用户ID、请求参数等信息。比如Java应用常用的SkyWalking探针,会自动采集JDBC层面的SQL执行信息,和TraceId绑定。
2. 实时告警能力
APM通常支持自定义阈值告警,可以配置当单条SQL执行耗时超过500ms,或者单位时间内慢SQL数量超过阈值时触发告警,第一时间通知运维人员介入。
3. 聚合统计能力
APM可以对采集到的SQL进行归一化处理,将不同参数的同一条SQL模板聚合起来,统计其平均耗时、最大耗时、调用次数等指标,快速识别高频慢SQL。
不过APM的短板在于不会保存SQL执行的完整上下文,比如具体的执行计划、是否命中索引等数据库层面的细节,这部分信息需要结合日志补充。
三、日志在慢查询分析中的补充作用
日志主要分为应用日志和数据库日志两类,两者结合可以补全APM缺失的信息:
1. 应用日志的补充
我们可以在应用层打印更详细的SQL执行日志,包含SQL的完整参数、执行开始和结束时间戳、返回的数据行数等信息,通过TraceId和APM采集的数据关联。比如可以在MyBatis的拦截器中添加日志打印逻辑:
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Statement;
import java.util.Properties;
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, org.apache.ibatis.session.ResultHandler.class})})
public class SqlLogInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(SqlLogInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = invocation.proceed();
long endTime = System.currentTimeMillis();
long cost = endTime - startTime;
// 将TraceId和SQL耗时、执行信息打印到日志中
logger.info("trace_id:{}, sql_cost:{}ms, execute_result:{}", TraceContext.getTraceId(), cost, result);
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
2. 数据库日志的补充
开启数据库的慢查询日志,可以获取数据库层面记录的慢SQL信息,包含SQL的执行计划、是否使用索引、锁等待时间等核心信息。以MySQL为例,开启慢查询日志的配置如下:
-- 开启慢查询日志 SET GLOBAL slow_query_log = 'ON'; -- 设置慢查询阈值,单位为秒,这里设置为0.5秒即500ms SET GLOBAL long_query_time = 0.5; -- 设置慢查询日志存储路径 SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
MySQL的慢查询日志中会记录SQL的执行时间、锁时间、返回行数、执行计划等详细信息,这些信息可以和APM采集的TraceId通过时间范围、SQL模板进行关联。
四、APM与日志结合的分析流程
完整的慢查询监控分析流程可以分为以下步骤:
1. 数据采集阶段
同时开启APM探针、应用SQL日志、数据库慢查询日志的采集,确保三者的时间同步,并且都携带可以关联的标识(比如TraceId、时间戳、SQL模板哈希)。
2. 告警触发阶段
当APM检测到慢SQL告警时,首先记录对应的TraceId、SQL模板、执行耗时、触发接口等信息。
3. 关联分析阶段
第一步先通过TraceId查询应用日志,获取该次请求中SQL的完整参数、返回行数等信息;第二步通过SQL模板和时间范围查询数据库慢查询日志,获取该SQL的执行计划、索引使用情况等信息。
4. 优化验证阶段
根据关联得到的信息进行SQL优化,比如添加索引、改写SQL逻辑等,优化后再次通过APM和日志观察SQL的耗时变化,验证优化效果。
五、实践注意事项
在实际落地过程中需要注意以下几点:
- 日志量控制:应用层打印SQL日志时要避免打印过多无用信息,生产环境可以只打印耗时超过阈值的SQL日志,避免磁盘和IO压力过大
- 数据留存:APM的明细数据通常只留存7-15天,慢查询的日志建议留存30天以上,方便排查周期性问题
- SQL脱敏:日志中如果包含敏感数据,比如用户手机号、身份证号等,需要对参数进行脱敏处理,避免信息泄露
- 阈值动态调整:慢查询的阈值不要固定不变,可以根据业务的实际运行情况动态调整,比如核心接口的阈值可以设置得更低
通过APM和日志的结合,我们可以覆盖SQL慢查询从发现到优化的全流程,既保证了监控的实时性和链路完整性,又补全了数据库层面的执行细节,大幅降低慢查询的排查难度。