#大致的业务场景
从一个报警表中查询数据,报警表中有很多其他表的外键,比如报警的设备信息信息,报警的组织信息,报警的原件信息等等,也就是说查询报警信息的时候可以查出来很多相关的信息,需求是参数传一个组织id,要求查询当前组织以及子组织的报警,同时实现分页返回的功能,根据当前组织查询子组织在数据库中是有函数实现的。
# 最初的实现(超慢的那种)
从报警表中查出所有信息,然后根据外键再去其他表中查询相关的信息,比如设备具体信息等。由于客户端分页需要返回符合查询条件的总条数,所以还有一个count(1)的service; 写完之后测试,发现几千条的数据竟然查询了4s,这。。。。。。简直是不能忍啊,于是开始查找原因。
# 分析原因
思路很简单,就是一部分一部分的查看运行时间,找出耗费时间长的代码,最后发现3s是由于count(1), 也就是查询总条数所耗费的时间,没理由啊,走索引的话几千条应该是毫秒级别的啊,直接在数据库运行count(1)的sql发现需要1.5s左右,这。。。。。。。。为啥到代码中就变成3s了???最后发现有一个逻辑是计算总页数的代码,大致是这样写的
if(aaService.getTotalNum % pagesize == 0){ totalPage = aaService.getTotalNum / pageSize; }else{ totalPage = aaService.getTotalNum / pageSize +1; }
wtfk???
这不就相当于调用了两次数据库吗???脑残。。。嗯,说的就是你。。。。
于是改呀改的,好了,喜闻乐见,直接减少了50%的时间,嗯,初步取得一点成就,还是很开心的
但是。。。。。。。。。。。。 又一想,
这才几千条数据就1s多,那像天猫这种nnnn多数据的岂不是要慢死,,但我并没有发现人家慢啊。。。
好吧,刚想飞上天和太阳肩并肩,瞬间就被拽回地面。。。
继续尝试,之前的sql查询类似是这样的:
select count(1) from 报警表 where find_in_set(组织id, 查询当前组织以及子组织的函数(当前组织id));
我试着吧where条件去掉,一查,我的哥。。。。。。。。。150ms,,这。。。。。。凌乱了,全表count竟然比部分还快。。。
猜测原因,应该是因为使用了查询子组织的函数,导致count没有走索引,,,,,
好了,既然找到罪魁祸首了,就好办了,先查询出来子组织然后再使用
select count(1) from 报警表 where 组织id in ();
果然,瞬间下降到150ms,哈哈哈,老天不负我,。。。。。。。。。
再回到上文,那还有其他的1s是怎么出来的呢,
还记得我们是先把报警表的数据查出来然后在根据外键去查询他的具体信息的吧,发现,有很多很多次连接数据库的操作。
所以稍稍优化一下,在查询报警的sql 中直接left join 其他表,把需要的相关数据在一条sql 中直接查出来,
其实就优化了这么多,但是这个查询就从4s直接降到了150ms,效果那是相当的显著,一口气都可以爬5楼了。。
# 总结一下,其实这次优化使用的方法并不多
第一个就是尽量减少连接数据库的次数,特别注意的是千万不要在循环中去连接数据库查询
第二个就是注意使用数据库的索引
最近老加班。。。。。。这还是从王者荣耀中省下来的时间码的字,写的很粗糙,若有客官看到,还请见谅。。。