平时常见的最后两种:Using filesort,Using temporary
(1)Using filesort 和 Using temporary:
在Order by中如果排序字段是有索引的,那么是直接可以从索引里按照排序字段排序顺序去查找数据的,比如这个SQL:
EXPLAIN SELECT * FROM t1 ORDER BY x1 LIMIT 10 ,这是典型的一个排序后再分页的语句,执行计划如下:
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | index | NULL | index_x1 | 458 | NULL | 10 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
直接使用索引,index_x1,在索引里按照顺序找LIMIT 10 要求的10条数据。
但是如果没有索引,此时就会基于内存或者磁盘文件来排序,大部分时候基于磁盘文件来排序,比如:
EXPLAIN SELECT * FROM t1 ORDER BY x2 LIMIT 10,x2字段是没有索引的,此时执行计划如下:
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 4578 | 100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
这个SQL很明确,他基于x2字段来排序,是没法直接根据有序的索引去找数据的,只能把所有数据都写入一个临时的磁盘文件,基于排序算法在磁盘文件里按照x2字段的值来完成排序,然后
再按照LIMIT 10 的要求,所以注意一下,这种把表全数据放磁盘文件排序的做法真的很糟糕,性能是极差的。
如果我们用group by,union,distinct之类的语法的时候,万一没法直接利用索引来进行分组聚合,那么他会直接基于临时表来完成,也会有大量的磁盘操作,性能也是极差的。
比如:EXPLAIN SELECT x2,COUNT(*) AS amount FROM t1 GROUP BY x2 ,这里的x2是没有索引的,所以此时执行计划如下:
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 5788 | 100.00 | Using temporary |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
这个SQL里只能对全表数据放到临时表做大量的磁盘文件操作,然后才能完成对x2字段的不同的值分组,分组完成了后对不同x2值的分组做聚合操作,这个过程也是相当耗时,性能极低的。
(2)总结:
所以记住,其实未来在SQL调优时,核心就是分析执行计划哪些地方出现了全表扫描,或者扫描数据过大,尽可能通过合理优化索引保证执行计划每个步骤都可以基于索引执行,避免
扫描过多的数据。