分析:从key_len=66,ref=const,const可以看出来,查询使用了c1和c2索引,由于使用了c4进行排序,跳过了c3,中间断了,也无法使用c4的索引进行排序,出现了Using filesort。
Case 4:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c5='a5' ORDER BY c2,c3
分析:查找只用到索引c1,c2和c3索引用于排序,无Using filesort。
Case 4.1:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c5='a5' ORDER BY c3,c2
分析:和Case 4中explain的执行结果一样,但是出现了Using filesort,因为索引的创建顺序为c1,c2,c3,c4,但是排序的时候c2和c3颠倒位置了。
Case 4.2:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c2='a2' ORDER BY c2,c3
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c2='a2' AND c5='a5' ORDER BY c2,c3
分析:在查询时增加了c5,但是explain的执行结果一样,因为c5并未创建索引。
Case 4.3:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c2='a2' AND c5='a5' ORDER BY c3,c2
分析:与Case 4.1相比,在Extra中并未出现Using filesort,因为c2是常量,在排序中被优化,所以索引未颠倒,不会出现Using filesort。
Case 5:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c4='a4' GROUP BY c2,c3
分析:如果gourp by没有使用索引,会导致生成临时表(Using temporary),底层会先用order by排序,要想group by使用索引分组,前提条件是满足order by使用索引排序。上面只用到c1上的索引进行查询,因为c4中间断了,根据索引最左前缀原则,索引key_len=33,ref=const,表示只用到一个索引。
Case 5.1:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1='a1' AND c4='a4' GROUP BY c3,c2
分析:对比Case 5,在group by时交换了c2和c3的位置,导致无法满足order by(Using filesort),即无法满足group by(Using temporary),极度恶劣。原因:c3和c2与索引创建顺序相反。
Case 6:
执行SQL语句:EXPLAIN SELECT * FROM test WHERE c1>'a1' ORDER BY c1
分析:
① 在c1,c2,c3,c4上创建了索引,直接在c1上使用范围,导致了索引失效,全表扫描:type=ALL,ref=NULL。因为此时c1主要用于排序,并不是查询。
② 使用c1进行排序,出现了Using filesort。
③ 解决方法:使用覆盖索引。
执行SQL语句:EXPLAIN SELECT c1 FROM test WHERE c1>'a1' ORDER BY c1
Case 7:
执行SQL语句:
EXPLAIN SELECT c1 FROM test ORDER BY c1 ASC, c2 DESC
分析:虽然排序的字段列与索引顺序一样,且order by默认升序,这里c2 DESC变成了降序,导致与索引的排序方式不同,从而产生Using filesort。
Case 8:
执行SQL语句:EXPLAIN SELECT c1 FROM test WHERE c1 IN('a1','b1') ORDER BY c2,c3
分析:对于排序来说,多个相等条件也是范围查询。
总结:
① MySQL支持两种方式的排序filesort和index,Using index是指MySQL扫描索引本身完成排序。index效率高,filesort效率低。
② order by满足两种情况会使用Using index:
a. order by语句使用索引最左前列。
b. 使用where子句与order by子句条件列组合满足索引最左前列。
③ 尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最佳左前缀原则。
④ 如果order by的条件不在索引列上,就会产生Using filesort。