在MySQL中,优化order by语句的核心思路是避免出现文件排序(Filesort),利用索引直接返回有序数据。
MySQL中的两种排序方式:
-
通过有序索引顺序扫描直接返回有序数据
因为InnoDB存储引擎中索引的结构是B+树,索引中的数据都是按照一定顺序进行排列了的,所以在排序查询中如果能利用索引,就能避免额外的排序操作,在用explain关键字进行sql分析时,Extra列会显示为Using Index。
-
Filesort排序,对返回的数据进行排序
通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的操作都是Filesort排序,也就是说进行了额外的排序操作,在用explain关键字进行sql分析时,Extra列会显示为Using filesort。
下面直接上案例:
我们这张seat表中的seat_type字段是没有索引的,所以会用到排序缓冲区,也就是把数据读出来,然后在排序缓冲区中进行排序,最后展示出来。其实 MySQL 会给每个线程分配一块内存用于排序,称为 sort_buffer。按 seat_type排序这个步骤,可能在内存中完成,也可能需要使用外部排序,这取决于排序所需的内存和参数 sort_buffer_size。也就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存顶不住,就得磁盘临时文件辅助排序。
那我们该怎么将Using filesort优化为Using index呢,这时候就要加索引了,如下:
ALTER TABLE seat ADD INDEX idx_col_code_seat_type ( `col_code`,`seat_type` );
我们再来看看执行计划有什么变化:
这时候就可以很清楚的看到使用的key为我们创建的索引,由之前的Using filesort变为了Using index了,性能比较高了。
我们再来看一种情况,我们将seat_type和col_code作为排序条件,大家发现没有,我们是把seat_type放在前面,col_code放在后面,来看下explain结果:
大家可以看到,order by使用条件的时候,也需要满足最左前缀原则,不然就会出现Using filesort。因为我们在创建索引的时候,col_code是第一个字段,seat_type是第二个字段,所以排序的时候,也要按照这个顺序来。