拿到一个sql,同事告诉我这个sql索引加了,为什么还是这么慢。
sale_order_goods,sale_order 两张表都有几十万的数据。其中in结果集有30万。
sql如下:
这是一个in + 子查询的语句。
顺便提一句,innodb对in + 子查询的处理非常差,比如:
这时,子查询关联外部表a,所以innodb认为无法执行这个子查询,于是需要全表遍历一遍a,再根据a返回的oid逐个执行一次子查询。
上面这个sql不需要执行子查询,改写如下:
直接放弃 in + 子查询的方式。sql在1秒内执行完毕。
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秒内执行完毕。