背景
昨天老大给我分了个活,在日志文件中发现,某条SQL执行耗时14秒左右,我接受到的任务就是优化之,在这里记录一下
原始SQL
select rel.COMPANY_ID as companyId,account.appid,account.mobile, account.customer_id as customerId
from tb_account account
left join tb_account_bank_rela rel on account.customer_id = rel.customer_id
where account.status = '1'
and (select count(1) from tb_union_merchant_product product where product.company_id= account.COMPANY_ID)>=20
and DATE_FORMAT(account.create_date, '%Y-%m-%d') = date_sub(curdate(), interval 3 day);
查了一下代码逻辑,主要是筛选满足条件的客户信息,筛选条件为:状态正常且归属公司下必须要有20以上个商品,且三天前注册的客户信息。
优化策略
- 优化子查询
原sql在where语句中使用了子查询,这肯定是个优化点,于是我把其中的这个子查询去除之后,重新执行了sql
可见,我们的优化重点确实在该子查询上面。我们可以使用连接语句替换掉子查询语句 - 索引
除此之外,最好是在where语句中的条件都是索引字段,这样可以增加查询速度;where后面有三个条件,单表字段为account.status、create_date,可以将他们这两个字段设为索引字段
优化后SQL
select rel.COMPANY_ID as companyId,account.appid,account.mobile, account.customer_id as customerId
from tb_account account
left join tb_account_bank_rela rel on account.customer_id = rel.customer_id
left join (select company_id,count(1) as productNum from tb_union_merchant_product group by company_id) comp on comp.company_id=account.company_id
where account.status = '1'
and comp.productNum>20
and DATE_FORMAT(account.create_date, '%Y-%m-%d') = date_sub(curdate(), interval 3 day);
跟原始SQL对比,区别最大的where语句中的子查询换成了连接查询,因为需要对数量进行过滤,所以组建了一张临时表作为关联表;除此之外,status字段和creat_date字段可以添加上查询索引,优化后的sql执行时间为:
优化了接近100倍,当数据量越大时,这种差距就越明显;我找了之前写原始SQL的同事问了,当时做开发时,SQL执行是根本就没那么慢的,原因就在于当时是用的是开发环境,数据较少,但是到了生产环境,这种查询效率很显然就低了不少。
总结
其实,本次优化的点主要是在优化查询语句和索引上面,没有什么高大上的东西;SQL优化是很大的面,策略也有很多,根据不同的场景,策略肯定不一样,尤其是面对海量数据,再小的优化点也会被放的很大。
除此之外,我理解的sql优化的工作,不仅面对的是SQL,更多的应该是面向业务,从业务层面到数据层面来思考,慢SQL如何正确的重构,我们优化的目标就是使新SQL又快又准。
不断总结,不断记录,希望以后会越来越精通。