背景:
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%’ 时,性能表现不一致。怀疑与内存命中率相关,但现在无法考证,下次再考证。