MySQL如何避免Using temporary; Using filesort,以提升查询效率

背景:
MySQL:8.0.15
引擎:innodb
A表数量:2600万

一、现象
语句:
select a.id,a.goods_id,a.goods_name,a.goods_state,a.is_delete
from a INNER JOIN b on a.series_id=b.series_id
where
a.is_delete = 0 AND a.supplier_id IN (1,2) AND b.cate_code LIKE ‘101%’ AND a.goods_state = 1 ORDER BY a.id asc LIMIT 0,50 ;

该语句在正式环境(a表2600万数据 MySQL 8.0.15)与在测试环境(a表10万数据,MySQL 5.6)的执行计划不一致,如下:
测试环境:
1 SIMPLE a index idx_series_id,idx_supplier_id PRIMARY 4 99 Using where
1 SIMPLE b eq_ref PRIMARY PRIMARY 4 zyddb.a.series_id 1 Using where
正式环增:
1 SIMPLE b range PRIMARY,idx_cate_code idx_cate_code 92 8031 100 Using where; Using index; Using temporary; Using filesort
1 SIMPLE a p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31 ref idx_series_id,idx_supplier_id,idx_union_001 idx_series_id 4 zyddb.b.series_id 306 25 Using where

因正式环境与测试环境配置不相同,也不能得武断得出结论说MySQL依据数据量大小而采取的不同的查询计划,但确实看到的查询计划是不一样的。(条件字段都有索引,排序字段为主键)

二、要解决的问题
在正式环境中,两张表内联查询的计划有Using temporary; Using filesort,这是导致效率下降的原因之一。
修改SQL语句,将order by 字段 作为查询条件之下,优化如下:
select a.id,a.goods_id,a.goods_name,a.goods_state,a.is_delete
from a INNER JOIN b on a.series_id=b.series_id
where
a.is_delete = 0 AND a.supplier_id IN (1,2) AND b.cate_code LIKE ‘101%’ AND a.goods_state = 1 and a.id>0 ORDER BY a.id LIMIT 0,50 ;
查询计划如下:
1 SIMPLE a p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31 range PRIMARY,idx_series_id,idx_supplier_id,idx_union_001,idx_id_desc PRIMARY 4 11543513 0.07 Using where
1 SIMPLE b eq_ref PRIMARY,idx_cate_code PRIMARY 4 zyddb.a.series_id 1 50 Using where

三、效果
A表:2600万+ B表:1.6万+
优化前的语句:
select a.id,a.goods_id,a.goods_name,a.goods_state,a.is_delete
from yjl_goods_price a INNER JOIN yjl_goods_series b on a.series_id=b.series_id
where
a.is_delete = 0 AND a.supplier_id IN (1,2) AND b.cate_code LIKE ‘101%’ AND a.goods_state = 1 ORDER BY a.id LIMIT 0,50 ;
执行计划:
1 SIMPLE b range PRIMARY,idx_cate_code idx_cate_code 92 8031 100 Using where; Using index; Using temporary; Using filesort
1 SIMPLE a p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31 ref idx_series_id,idx_supplier_id,idx_union_001 idx_series_id 4 zyddb.b.series_id 306 25 Using where
执行时间:200s以上,未执行完毕,强制结束

优化后的语句:
select a.id,a.goods_id,a.goods_name,a.goods_state,a.is_delete
from a INNER JOIN b on a.series_id=b.series_id
where
a.is_delete = 0 AND a.supplier_id IN (1,2) AND b.cate_code LIKE ‘101%’ AND a.goods_state = 1 and a.id>0 ORDER BY a.id LIMIT 0,50 ;
执行计划:
1 SIMPLE a p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31 range PRIMARY,idx_series_id,idx_supplier_id,idx_union_001,idx_id_desc PRIMARY 4 11543513 0.07 Using where
1 SIMPLE b eq_ref PRIMARY,idx_cate_code PRIMARY 4 zyddb.a.series_id 1 50 Using where
执行时间:0.1s以内

总结:
1、让排序字段,加入到条件语句中,哪怕是硬植入也是必要的。
2、至于小表驱动大表,大表驱动小表,也试进行的验证,没有明显的差别。(inner join两表的表位置互换,数据量少的在inner join前,称为小表驱动大表)

疑问:
select a.id,a.goods_id,a.goods_name,a.goods_state,a.is_delete,a.supplier_id,a.cate_code
from a INNER JOIN b on a.series_id=b.series_id
where
a.is_delete = 0 AND a.supplier_id IN (1,2) AND b.cate_code LIKE ‘201110%’ AND a.goods_state = 1 and a.id>0 ORDER BY a.id desc LIMIT 0,50 ;
同样是这个语句,当修改b.cate_code like ‘201%’ 、b.cate_code like ‘20111%’ 、b.cate_code like ‘201110%’ 时,性能表现不一致。怀疑与内存命中率相关,但现在无法考证,下次再考证。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值