第十六讲

145 阅读4分钟

排序

如果语句需要排序,MySQL会给每个线程分配一块内存用于排序,称为sort_buffer。

排序的流程

  • 初始化sort_buffer,确定放入指定查询的字段
  • 从索引中获取满足条件的记录和对应字段,(二级索引再回表)
  • 取完满足条件的记录后对sort_buffer中的数据按照字段name做快速排序
  • 将结果集返回

排序这个动作,可能在内存中完成,也可能需要使用外部排序,这取决于排序所需的内存和参数sort_buffer_size。

sort_buffer_size,就是MySQL为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于sort_buffer_size,排序就在内存中完成。反之则在磁盘临时文件中辅助排序(外部排序)。

通过查看 OPTIMIZER_TRACE 的结果来确认是否使用了临时文件

SET optimizer_trace='enabled=on'; 
*** 查找语句 ***
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G
  • number_of_tmp_files表示的是,排序过程中使用的临时文件数。内存放不下时,就需要使用外部排序,外部排序一般使用归并排序算法

    如果需要排序的数据量超过sort_buffer_size,那么临时文件就会按照sort_buffer_size的大小,分成多个临时文件,最后组成一个大的有序文件。没超过则临时文件数为0. 多个临时文件,排序的性能会很差

  • examined_rows 表示参与排序的行数

  • sort_mode < sort_key, packed_additional_fields > packed_additional_fields表示排序过程对字符串做了“紧凑”处理。

  • 查询OPTIMIZER_TRACE这个表时,需要用到临时表,而internal_tmp_disk_storage_engine的默认值是InnoDB。InnoDB引擎的话,把数据从临时表取出来的时候,会让Innodb_rows_read的值加1。可以设置internal_tmp_disk_storage_engine设置成MyISAM来避免这种情况出现。

排序性能优化

max_length_for_sort_data,是MySQL中专门控制用于排序的行数据的长度的一个参数。它的意思是,如果单行的长度超过这个值,MySQL就认为单行太大,要换一个算法。

rowid排序

如果数据行的长度过长(超出max_length_for_sort_data),从而影响排序过程中的性能表现,mysql会采取先将排序列与id 放入sort_buffer里面,然后排序完成再通过id回表获取指定的数据列。此时参与排序的就只有name和id这两个字段。

MySQL的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问。rowid排序会要求回表多造成磁盘读,因此不会被优先选择。

保证数据原生的有序性

也可以用覆盖索引,让索引上的信息足够满足查询请求,不需要再回到主键索引上去取数据。(“Using index”,表示的就是使用了覆盖索引,性能上会快很多。)

评论精选

全字段排序

1.通过索引将所需的字段全部读取到sort_buffer中 2.按照排序字段进行排序 3.将结果集返回给客户端

缺点: 1.造成sort_buffer中存放不下很多数据,因为除了排序字段还存放其他字段,对sort_buffer的利用效率不高 2.当所需排序数据量很大时,会有很多的临时文件,排序性能也会很差

优点: MySQL认为内存足够大时会优先选择全字段排序,因为这种方式比rowid 排序避免了一次回表操作

rowid排序

1.通过控制排序的行数据的长度来让sort_buffer中尽可能多的存放数据,max_length_for_sort_data 2.只将需要排序的字段和主键读取到sort_buffer中,并按照排序字段进行排序 3.按照排序后的顺序,取id进行回表取出想要获取的数据 4.将结果集返回给客户端

优点:更好的利用内存的sort_buffer进行排序操作,尽量减少对磁盘的访问

缺点:回表的操作是随机IO,会造成大量的随机读,不一定就比全字段排序减少对磁盘的访问