前言
最近我在公司优化了一些慢查询SQL,积累了一些SQL调优
的实战经验。
我之前写过一些SQL优化相关的文章《聊聊SQL优化的15个小技巧》和《explain | 索引优化的这把绝世好剑,你真的会用吗?》,在全网广受好评。
这篇文章从实战的角度出发,给大家分享一下如何做SQL调优。
经过两次优化之后,慢SQL的性能显著提升了,耗时从8s
优化到了0.7s
。
现在拿出来给大家分享一下,希望对你会有所帮助。
1 案发现场
前几天,我收到了一封报警邮件,提示有一条慢查询SQL。
我打开邮件查看了详情,那条SQL大概是这样的:
SELECTcount(*)
FROMspus1
WHEREEXISTS(
SELECT*
FROMskus2
INNERJOINmall_skus3ONs3.sku_id=s2.id
WHEREs2.spu_id=s1.id
ANDs2.status=1
ANDNOTEXISTS(
SELECT*
FROMsupplier_skus4
WHEREs4.mall_sku_id=s3.id
ANDs4.supplier_id=123456789
ANDs4.status=1
)
)
这条SQL的含义是统计id=123456789的供应商,未发布的spu数量是多少。
这条SQL的耗时竟然达标了8s
,必须要做优化了。
我首先使用explain
关键字查询该SQL的执行计划
,发现spu表走了type类型的索引,而sku、mall_sku、supplier_sku表都走了ref类型的索引。
也就是说,这4张表都走了索引
。
不是简单的增加索引,就能解决的事情。
那么,接下来该如何优化呢?
2 第一次优化
这条SQL语句,其中两个exists
关键字引起了我的注意。
一个exists
是为了查询存在某些满足条件的商品,另一个not exists
是为了查询出不存在某些商品。
这个SQL是另外一位已离职的同事写的。
不清楚spu表和sku表为什么不用join,而用了exists。
我猜测可能是为了只返回spu表的数据,做的一种处理。如果join了sku表,则可能会查出重复的数据,需要做去重处理。
从目前看,这种写性能有瓶颈。
因此,我做出了第一次优化。
使用join
+group by
组合,将sql优化如下:
SELECTcount(*)FROM
(
selects2.spu_idfromspus1
innerjoinfromskus2
innerjoinmall_skus3ons3.sku_id=s2.id
wheres2.spu_id=s1.idands2.status=1
andnotexists
(
select*fromsupplier_skus4
wheres4.mall_sku_id=s3.id
ands4.supplier_id=...
)
groupbys2.spu_id
)a
文章中有些相同的条件省略了,由于spu_id在sku表中是增加了索引的,因此group by的性能其实是挺快的。
这样优化之后,sql的执行时间变成了2.5s
。
性能提升了3倍多,但是还是不够快,还需要做进一步优化。
3 第二次优化
还有一个not exists可以优化一下。
如果是小表驱动大表的时候,使用not exists确实可以提升性能。
但如果是大表驱动小表的时候,使用not exists可能有点弄巧成拙。
这里exists右边的sql的含义是查询某供应商的商品数据,而目前我们平台一个供应商的商品并不多。
于是,我将not exists改成了not in。
sql优化如下:
SELECTcount(*)FROM
(
selects2.spu_idfromspus1
innerjoinfromskus2
innerjoinmall_skus3ons3.sku_id=s2.id
wheres2.spu_id=s1.idands2.status=1
ands3.idnotIN
(
selects4.mall_sku_id
fromsupplier_skus4
wheres4.mall_sku_id=s3.id
ands4.supplier_id=...
)
groupbys2.spu_id
)a
这样优化之后,该sql的执行时间下降到了0.7s。
之后,我再用explain关键字查询该SQL的执行计划。
发现spu表走了全表扫描,sku表走了eq_ref类型的索引,而mall_sku和supplier_sku表走了ref类型的索引。
可以看出,有时候sql语句走了4个索引,性能未必比走了3个索引好。
多张表join的时候,其中一张表走了全表扫描,说不定整个SQL语句的性能会更好,我们一定要多测试。
说实话,S服务器托管网QL调优是一个比较复杂的问题,需要考虑的因素有很多,有可能需要多次优化才能满足要求。
最后说一句(求关注,别白嫖我)
如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
关注公众号:【苏三说技术】,在公众号中回复:面试、代码神服务器托管网器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
1. HashMap的家族定位 接口java.util.Map有四个常用的实现类,如图是它们之间的类继承关系。 下面我将一一介绍其性能特点。 HashMap: 最常用的Map实现类,通过使用Hash表结构,提高查找速度; 使用键值对作为存储节点,只允许一个ke…