背景
昨天老大给我分了个活,在日志文件中发现,某条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又快又准。
不断总结,不断记录,希望以后会越来越精通。