代码片段:自己动手写SQL慢查询统计

前言

首先,MySQL是有自己的慢查询日志记录的,但是作为开发者,并不一定有权限查看MySQL的日志。因此可以自己动手写个SQL慢查询统计,但这个实现方式所统计到的时间是包含网络开销的,不过在正常情况下,没啥关系,根据统计也能分析到一定原因,主要是这种方式我们能实时监控SQL的大致执行时间,然后有针对的进行SQL优化,能尽快的发现一些问题。

代码实现

  • 切面
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author itoak
 */
@Aspect
public class SlowQueryMonitorAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final Long THRESHOLD = 500L;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    private Executor executor = Executors.newSingleThreadExecutor();
	
	/**
    * 第一个 * 号表示接口返回类型为任意类型
    * dao后面的 .. 表示dao包以及子包
    * 第二个 * 表示任意接口
    * 第三个 * 表示任意函数名
    * 最后括号内 .. 表示任意参数
    */
    @Pointcut("execution(* cn.itoak.storm.dao..*.*(..))")
    public void monitorPointCut(){}

    @Around("monitorPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String declaringType = joinPoint.getSignature().getDeclaringTypeName();
        long start = System.currentTimeMillis();
        Object object = joinPoint.proceed();
        long end = System.currentTimeMillis() - start;
        if (logger.isInfoEnabled() && end > THRESHOLD) {
            String sql = sqlSessionFactory.getConfiguration().getMappedStatement(declaringType + "." + methodName).getBoundSql(null).getSql();
            logger.info("==> Preparing:{}", sql);
            logger.info("==> Parameters:{}", Arrays.toString(joinPoint.getArgs()));
            logger.info("<== Time consuming:{} ms", end);

            //异步保存到DB,让切面对主流程影响降到最低
            executor.execute(() -> {
                //保存到DB
            });
        }
        return object;
    }
}
  • 配置
import cn.itoak.storm.aspects.SlowQueryMonitorAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @author itoak
 */
@Configuration
@EnableAspectJAutoProxy
public class AspectConfig {
    @Bean
    public SlowQueryMonitorAspect slowQueryMonitorAspect(){
        return new SlowQueryMonitorAspect();
    }
}
  • 结果
c.i.s.aspects.SlowQueryMonitorAspect     : ==> Preparing:select * from z_per where id = ?
c.i.s.aspects.SlowQueryMonitorAspect     : ==> Parameters:[1]
c.i.s.aspects.SlowQueryMonitorAspect     : <== Time consuming:522 ms

注释:代码中THRESHOLD阈值设置的500L ms是为了看到效果,需要自行更改为合适的值。MySQL官方定义慢查询的时间是10S,但是这个时间已经很长了,所以读者根据自己系统的性能要求设置合理的阈值即可。

原创文章 67 获赞 31 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012534326/article/details/103288676