MySQL之order by
假设执行explain select * from a, b, c from tb where a = ? order by b limit 1000;
key:a
extra:Using filesort
全字段排序
排序过程:
- MySQL的server层为每一个线程分配一块内存sort_buffer用于排序
- 初始化sort_buffer确定放入字段a、b、c,也就是select的字段
- 走索引a找到第一个满足条件的主键id,并回表查询a、b、c放入到sort_buffer中
- 遍历索引a,找到所有满足条件的,重复3过程(放不进去怎么办?)
- 对sort_buffer中的数据进行排序,并返回前1000行
对于步骤4中问题,放不放的进去取决于sort_buffer_size的值,如果数据大于该值则需要利用磁盘临时文件辅助排序,即外部排序。经典问题:内存只有1G,我有40G的数据该如何排序?
rowid排序
简单的说就是,sort_buffer中只存在排序的字段和主键,这样就能向sort_buffer中放更多的值,排完序后回表查询1000行的a、b、c并返回,相比于全字段排序会多一次回表的过程
全字段 or rowid?
如果内存够大或者数据量不大,即排序的数据都能放到内存中且对现有的系统不会造成太大的影响,那么MySQL会选择使用rowid,即尽可能的减少IO的次数
如何优化?
- 加索引(a, b)这样就可以直接走索引
- 加索引(a, b, c)这样不光不用排序,而且还不用回表
参考
- 极客时间MySQL实战45讲,第16讲