order by 的两种排序
- 全字段排序
- 当用 explain 执行计划发现 Extra 这个字段中的值为 “Using filesort” 时表示的就是需要排序,MySQL会给每个线程分配一块内存用于排序,称为 sort_buffer。
-
按某个字段排序这个动作,可能在内存中完成,也可能需要使用外部排序,这取决于排序所需的内存和参数 sort_buffer_size。
sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。
-
内存放不下时,就需要使用外部排序,外部排序就需要使用磁盘临时文件辅助排序。外部排序一般使用归并排序算法,可以这么简单理解,MySQL 将需要排序的数据分成 12 份,每一份单独排序后存在这些临时文件中。然后把这 12 个有序文件再合并成一个有序的大文件。如果 sort_buffer_size 超过了需要排序的数据量的大小,则排序在内存中直接完成,如果不超过,就需要放在临时文件中排序,sort_buffer_size 越小,需要分成的份数越多。
- rowid 排序
- 全字段排序只对原表的数据读了一遍,剩下的操作都是在 sort_buffer 和临时文件中执行的。但全字段排序有一个问题,就是如果查询要返回的字段很多的话,那么 sort_buffer 里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能会很差。所以如果单行很大,这个方法效率不够好。
- max_length_for_sort_data,是 MySQL 中专门控制用于排序的行数据的长度的一个参数。它的意思是,如果单行的长度超过这个值,MySQL 就认为单行太大,要换一个算法。
- 只差查主键 id 到 sort_buffer 内存中, MySQL 服务端从排序后的 sort_buffer 中依次取出 id,然后到原表查到 需要的字段的结果,不需要在服务端再耗费内存存储结果,是直接返回给客户端的。与全字段排序相比需要回表一次。
-
对于InnoDB表来说,它使用的 InnoDB 引擎,执行全字段排序会减少磁盘访问,因此会被优先选择。
对于内存表,回表过程只是简单地根据数据行 rowid 的位置,直接访问内存得到数据,根本不会导致多访问磁盘,所以它是按 rowid 排序。
内存表是 MEMORY 引擎,MEMORY 引擎不是索引组织表。我们可以理解它就是一个数组。因此,这个 rowid 其实就是数组的下标
全字段排序 VS rowid排序
MySQL 优先选择全字段排序,rowid 排序是次选。
如果 MySQL 实在是担心排序内存太小,会影响排序效率,才会采用 rowid 排序算法,这样排序过程中一次可以排序更多行,但是需要再回到原表去取数据。
如果 MySQL 认为内存足够大,会优先选择全字段排序,把需要的字段都放到 sort_buffer 中,这样排序后就会直接从内存里面返回查询结果了,不用再回到原表去取数据。
MySQL 的设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问。内存快,磁盘慢。
并不是所有的 order by 语句,都是需要排序操作的。
从上面分析的执行过程,我们可以看到,MySQL 之所以需要生成临时表,并且在临时表上做排序操作,其原因是原来的数据都是无序的。
所以,如果能够保证从 where 条件的过滤字段的索引上取出来的行,天然就是按照某个字段排序的话,就可以不用再排序了。比如我们常在 createTime 字段上加上索引,因为 常按 createTime 来进行排序。
--------------------------------------------
记录一片写的很好的博客,备用