您的位置:首页 > 数据库

记一次sql优化,in+子查询

2017-10-17 17:44 381 查看
拿到一个sql,同事告诉我这个sql索引加了,为什么还是这么慢。

sale_order_goods,sale_order 两张表都有几十万的数据。其中in结果集有30万。

sql如下:

SELECT
ifnull(sum(buy_number), 0) AS buy_number_sum
FROM
sale_order_goods
WHERE
sale_order_id IN (
SELECT
so.id

FROM
sale_order_goods sog,
sale_order so
WHERE
1 = 1
AND sog.tenant_org_id =1
AND so.tenant_org_id =1
AND sog.sale_order_id = so.id

AND so.order_status =1
AND DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(sog.created_at)
);


这是一个in + 子查询的语句。

顺便提一句,innodb对in + 子查询的处理非常差,比如:
select * from a where a.oid in (select id from b where b.name='xxx')
,如果
select id from b where b.name='xxx'
返回的结果是1,2,3。那么sql是不是就变成了
select * from a where a.oid in (1,2,3)
. NO!!,事实上不是这样。innodb会把外层表压入到子查询中,sql会变成
select * from a exists (select * from b where name='xxx' and b.id = a.oid)


这时,子查询关联外部表a,所以innodb认为无法执行这个子查询,于是需要全表遍历一遍a,再根据a返回的oid逐个执行一次子查询。

上面这个sql不需要执行子查询,改写如下:

SELECT
ifnull(sum(buy_number), 0) AS buy_number_sum
FROM
sale_order_goods sog,
sale_order so
WHERE
1 = 1
AND sog.tenant_org_id =1
AND so.tenant_org_id =1
AND sog.sale_order_id = so.id

AND so.order_status =1
AND DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(sog.created_at)


直接放弃 in + 子查询的方式。sql在1秒内执行完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: