排序
如果语句需要排序,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,会造成大量的随机读,不一定就比全字段排序减少对磁盘的访问