前言
今天做项目时,遇到需要用到子查询的地方。但是使用子查询后查询效率很低,在网上找资料后,了解到 子查询的执行效率居然受制于外层查询的记录数。
技术大牛的博客原文:点击查看大牛的SQL优化。
未优化之前的代码
select
c.customer_id,
a.union_id,
a.ip,
a.query_string,
b.name,
a.query_date,
a.has_result
from
customer_query a
left join
mat b on a.store_id = b.ip_id
inner join
customer c on a.customer_id = c.customer_id
where
a.`type` = 1 and a.query_date > '2019-05-01'
and exists (select 1 from order q where q.customer_id = c.customer_id);
其中我使用的是exists,这个比 in 效率高一点。但是存在子查询后,效率仍然很低。
未优化之前查询需要4秒钟时间。
解析查询语句:
由于子查询对 order 的查询方式依赖于外层 的查询,也就是可以分为两步:
select
c.customer_id,
a.union_id,
a.ip,
a.query_string,
b.name,
a.query_date,
a.has_result
from
customer_query a
left join
mat b on a.store_id = b.ip_id
inner join
customer c on a.customer_id = c.customer_id
where
a.`type` = 1 and a.query_date > '2019-05-01'
- 第一步,通过这个查询获得一个rows = 41290的结果集,
- 第二步,结果集里面的每一条数据再与子查询组成一个新的查询语句,也就是说,子查询要执行四万多次,所以这样效率就慢了。
优化策略
与临时表联合查询。
select
table1.customer_id,
table1.union_id,
table1.ip,
table1.query_string,
table1.name,
table1.query_date,
table1.has_result
from
(select
c.customer_id,
a.union_id,
a.ip,
a.query_string,
b.name,
a.query_date,
a.has_result
from
customer_query a
left join
mat b on a.store_id = b.ip_id
inner join
customer c on a.customer_id = c.customer_id
where
a.`type` = 1 and a.query_date > '2019-05-01') table1,
(select customer_id from order) table2
where table1.customer_id = table2.customer_id
把外查询作为一个表,再将子查询作为一个临时表,两个表联合查询。
此次查询结果如下:只花了0.079秒,成果优化。
结语
技术很多很杂,学会后很久不用还是会忘记,故作此记录,仅供自己回顾用,如果有错还望指正。