记一次mybatis性能问题分析过程

2023-02-12,,,

说明

今天发现个2个问题,一是mybatisplus执行一条某个字段值比较长(约1.8M的文本)的INSERT语句耗时要90s+;二是读取这个1.8M文本返回给前端耗时6min。查查查查了半天搞不清楚什么原因,最后在同事过来分析指点下立马解决。突然觉得自己像个沙比,特此记录,知耻后勇。另外也反思一下在查问题过程中的思路和方式问题。

问题1

现象

INSERT耗时过长

如图,SQL是单条记录更新,只不过第二个String比较大。下面是打印的耗时

当时分析思路

    想验证一下此条INSERT语句通过navicat执行需要多长时间?

        

    复制出来执行一下,发现navicat执行需要16s左右,且返回的数据库response显示实际执行2s多。感觉是navicat在执行前后做了些业务操作如分析文本,导致要十几秒
    验证原生jdbc执行效率

        

    通过原生jdbc执行多次发现执行时间在4s左右,还是相差甚远。开始怀疑是否mybatis是不是做了些文本分析才增加了耗时
    验证mybatis的代理类执行效率

        

    构建了一个最简单的mybatis来执行,效率与jdbc相似也在4s左右,说明并没有
    是否是事务等待?

        

    通过show processlist 和查询 information_schema.innodb_trx、innodb_locks、innodb_lock_waits发现执行此insert时并没有任何语句在执行,也就是说不存在事务等待
    开始懵逼?

        

    想不通,看到ExecuteTime 139ms,觉得可能是mybatis里面哪个方法有问题,开始疯狂debug,不停debug,业务代码弄一下,mybatis源码弄一下,真的懵逼
    寻求支援

        

    在同事的提示下猜测可能是打印日志拼接了过长的字符串所以耗时增加,原项目的日志等级不管怎么调,mybatis都在输出执行sql,无奈用回上面的 3 中的mybatis测试程序,将日志等级调整为ERROR,发现不输出日志和输出日志时间差异并不大,在10ms左右!然后我就放弃了思考。。。

后续解决

让同事过来帮忙一起看,他对于这个项目更熟悉,所以直接找到了mybatisplus的配置类,发现了一个PerformanceInterceptor,如下

此类中会打印执行的sql,难怪原项目怎么调日志等级都没用,原来在这里打印的

然后将此bean注释掉重新尝试一遍,那条执行时间长的 INSERT 立马丝滑,1s内就执行完成了。于是将此 bean 添加 @Profile("localdev") 注解,只在本地测试环境开启。

将代码提交后构建uat环境验证,结果无误,至此解决。

后续研究

本来想在本机复现,发现 PerformanceInterceptor 正常配置下只会打印 预编译sql,如下图

这样执行效率并没有受到影响,看来是某个实现将参数替换预编译中?的功能导致的低效问题。

这个替换功能目前网上主要是说要将log-impl设置为 StdOutImpl,但是尝试过无效,后续还是要找时间看看,不过可以不用太过纠结,毕竟这只是某个框架的配置的东西。

问题2

现象

1.8M左右的文本文件,将内容读取后以String返回,返回效率低花了6分钟。

分析过程

    对比分析

        

    首先还是尝试用一个测试的Springboot项目来返回此文本文件,以判断是否是网络或者其他原因。

    测试结果发现相应速度很快,在200ms内。即使加大文本量到18M,相应时间也在700多ms,所以不是框架或者网络等原因。
    怀疑是filter或者interceptor或者AOP处理response耗时过长

        

    项目内自定义的AOP过了一遍都没什么特别的处理。有两个自定义的与保留用户登录状态的token相关的filter,在他们的 chain.doFilter(request,response)方法前和该filter的 doFilter方法结尾都

    打印时间,发现第一个filter的start 和 end 隔得特别长,但是这个filter根本没做什么处理,就是一个 Map.remove的操作,所以肯定是有别的我没发现的filter在作怪。
    交给其他同事

        

    由于对这块配置包括springSecurty不熟,并且还有别的项目要开发,项目经理建议交给其他同事来查此问题。

后续解决

是fastjson中对于web框架的传参出参做了处理,导致慢的。

后续研究

tomcat中注册了哪些filter可以通过 chain 这个对象来看

总结

    最后回头来看,其实我对于问题的分析思路基本上都是正确的,就差在熟悉程度上,对于框架的操作使用,问题排查还是需要多写多练才能提升经验。
    不要被情绪影响,在查问题很大一部分影响因素是心态和情绪。当时的情况是有另一个项目需要开发,前端要找我对接;并且现场部署的产品有问题,报障群其他人都在装死;这个性能问题昨天已经解了一天,解决完部分问题后又冒出了这些新问题;

    这三连击加起来让我在不同的项目中来回切换,并且产生了焦躁情绪,甚至在怀疑自己,这些都会阻碍思考。
    后续做事要分清轻重缓急,并且心态要放平和,用观察者心态来处理情绪。还需要多积累分析解决问题的实际经验,分析问题中不要死磕去debug。

    至此

记一次mybatis性能问题分析过程的相关教程结束。

《记一次mybatis性能问题分析过程.doc》

下载本文的Word格式文档,以方便收藏与打印。