order by语句工作

5 分钟阅读 660 字 + 584 词
在where情况下,当order by 的字段不带索引:
全字段排序(单路排序)
  1. extra字段如果带有 using filesort 就需要排序,然后mysql会分配一块内存sort_buffer用来排序。(先准备sort_buffer用来排序)
  2. 先通过 辅助索引 找到 满足where条件 的主键id。(找主键id)
  3. 回表 主键索引树 中== 取出所有要求返回的字段值(可能是a,b,c) ==, 存入sort_buffer 中(回表取出要求的字段)
  4. 辅助索引找下一个记录的主键id ,重复上述操作直到不满足条件为止。
  5. sort_buffer中的数据按照==order by 的字段(可能就是a)==进行排序(排序直接返回即可)
如果 排序所需的内存 比sort_buffer_size还要大,就要使用外部排序,生成临时文件辅助排序。
rowid排序(==双路排序,需要回表操作==)
全字段排序如果查询的字段非常多 单行很大 ,那么需要分成很多临时文件,排序性能会很差。
所以==mysql中会判断 如果单行长度超过某个值 ,就会采用新的算法。==
新的算法 放入 sort_buffer 的字段,==只有 要排序的列和主键 id ==。
具体的步骤:
  1. 初始化sort_buffer ,放入两个字段,需要 排序的列和主键id
  2. 辅助索引 找到第一个满足条件的主键id,然后回表到主键索引树中取出 待排序的列(a)和主键id字段 ,放入sort_buffer中
  3. 继续从辅助索引找下个满足条件的主键id,重复步骤直到不满足条件为止。
  4. 对sort_buffer中的数据按照 order by 的字段 进行排序;
  5. 然后遍历排序结果,并按照主键id 回到主键索引中取出查找的字段(b和c)(==回表操作==)。
如果 MySQL 实在是 担心排序内存太小 ,会 影响排序效率 ,才会 采用 rowid 排序算法 ,这样排序过程中一次可以排序更多行, 但是需要再回到原表去取数据。
如果 MySQL 认为内存足够大 ,会优先选择 全字段排序 ,把 需要的字段都放到 sort_buffer 中 ,这样排序后就会直接从 内存里面返回 查询结果了, 不用再回到原表去取数据
这也就体现了 MySQL 的一个设计思想: 如果内存够,就要多利用内存,尽量减少磁盘访问。
如果order by的字段是带索引的。那么可以不需要临时表,也不需要排序了。
并且我们还可以使用索引覆盖进一步的提高效率,减少回表操作。
order by rand() 使用了内存临时表,内存临时表排序的时候使用了 rowid 排序方法。