MySQL之order by

optimjie / 2023-08-09 / 原文

假设执行explain select * from a, b, c from tb where a = ? order by b limit 1000;
key:a
extra:Using filesort

全字段排序

排序过程:

  1. MySQL的server层为每一个线程分配一块内存sort_buffer用于排序
  2. 初始化sort_buffer确定放入字段a、b、c,也就是select的字段
  3. 走索引a找到第一个满足条件的主键id,并回表查询a、b、c放入到sort_buffer中
  4. 遍历索引a,找到所有满足条件的,重复3过程(放不进去怎么办?
  5. 对sort_buffer中的数据进行排序,并返回前1000行

对于步骤4中问题,放不放的进去取决于sort_buffer_size的值,如果数据大于该值则需要利用磁盘临时文件辅助排序,即外部排序。经典问题:内存只有1G,我有40G的数据该如何排序?

rowid排序

简单的说就是,sort_buffer中只存在排序的字段和主键,这样就能向sort_buffer中放更多的值,排完序后回表查询1000行的a、b、c并返回,相比于全字段排序会多一次回表的过程

全字段 or rowid?

如果内存够大或者数据量不大,即排序的数据都能放到内存中且对现有的系统不会造成太大的影响,那么MySQL会选择使用rowid,即尽可能的减少IO的次数

如何优化?

  1. 加索引(a, b)这样就可以直接走索引
  2. 加索引(a, b, c)这样不光不用排序,而且还不用回表

参考

  1. 极客时间MySQL实战45讲,第16讲