MySQL html
随着业务量的增加,运营同事反馈有个报表页面愈来愈慢,从对应的报表语句中逐个子查询筛查,找出以下最慢的语句:mysql
能够看到,其中有个子集全表扫了300多万行数据。抽出来单独explain,定位到问题语句:sql
SELECT t1.statDate, t1.tips .net
FROM passport_4366_test t1 htm
WHERE t1.statDate>='2016-05-01' blog
AND t1.statDate<='2016-05-05' 索引
GROUP BY t1.statDate, t1.tips; ip
检查一下表结构发现,在表的statDate上明明创建了索引,照理说type应该是range才对,怎么会是all呢?get
去掉group by语句试试:
仍然是全表扫描。去掉一个字段再试试:
要扫描的数据量变成1/5,type也变成range了。那么究竟是什么缘由致使MySQL查询执行器放弃使用索引直接进行全表扫描呢?去问问谷歌,搜索到以下可能有帮助的文章:
回顾一下,这个表字段是date类型,难道是由于这个表同一天产生太多数据下降了索引区分度导致查询执行器放弃治疗?那么,把这个字段改为datetime类型会不会好点?好,咱们来动手试试看。
create table passport_4366_test like passport_4366;
insert into passport_4366_test select * from passport_4366 where statDate>='2016-04-01' AND statDate<='2016-05-06';
alter table passport_4366_test add index dt_idx(updateTime);
alter table passport_4366_test drop index statDate;
而后explain看看:
真是顽固不化的MySQL,只好force index了:
终于乖乖听话了。想起来还有一个解决思路,那就是创建联合索引:
alter table passport_4366_test add index statDate_tips_idx(statDate, tips);
再来看看explain的结果:
效果很不错,rows列比force index的结果还要好(多是由于Index Condition Pushdown Optimization)。拉大时间范围,直接执行语句对比一下执行时间:
结果是联合索引完胜。
最后,总结一下:
1. 创建索引时候尽可能选择区分度大的列;
2. 适当条件下能够考虑创建联合索引,譬如本例中联合索引的优点明显;
3. 写SQL的时候要多点explain,主要看type和rows,通常来讲,执行效率const > eq_ref > ref > range > all,rows值越少越好。
参考文章:
http://blog.csdn.net/mchdba/article/details/9190771
https://www.percona.com/blog/2014/01/03/multiple-column-index-vs-multiple-indexes-with-mysql-56/
http://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html