初学MySQL——order by的执行过程

order by是怎样执行的?

  • 全字段排序
  • rowid排序
  • 全字段排序VSrowid排序
  • 总结

以市民表为例,假设查询城市是上海所有人的名字,按照姓名排序返回前1000个人的姓名和年龄。

select city,name,age from t where city = '上海' order by name limit 1000;

全字段排序

explain select city,name,age from t where city = '上海' order by name limit 1000;

查看sql语句的执行情况,Extra字段中的"Using filesort"表示需要排序,MySQL会给每个线程分配一块内存用于排序,称为sort_buffer。

该语句的执行过程:

  1. 初始化sort_buffer,确定放入 city name age字段;
  2. 从索引city上找到第一个满足city='上海’条件的主键id;
  3. 从主键id索引上取出整行,取name,city,age三个字段的值,存入sort_buffer中;
  4. 从索引city取出下一个记录的主键id;
  5. 重复步骤3、4直到city的值不满足查询条件为止;
  6. 对sort_buffer中的数据按照字段name进行快速排序;
  7. 将排序结果取前1000行,返回给客户端;

初学MySQL——order by的执行过程_第1张图片
按name排序这个动作,可能在内存中完成,也可能需要使用外部排序,取决于排序内所需的内存和参数sort_buffer_size,排序的数据量小于sort_buffer_size就在内存中完成,如果数据量太大,就得用磁盘临时文件辅助排序。

rowid排序

如果查询要返回的字段很多,sort_buffer里面存放的字段数太多,内存里同时放下的行数很少,要分成很多文件,排序的性能会很差。

MySQL如何对排序的单行长度太大怎么办?

SET max_length_for_sort_data = 16;

max_length_for_sort_data,是MySQL中专门控制用于排序的行数据长度的一个参数,超过这个长度就要换另外一种算法,rowid排序。

初学MySQL——order by的执行过程_第2张图片
相比于全字段排序流程图,rowid排序多访问了一次表t的主键索引,遍历排序结果,取前 1000 行,并按照 id 的值回到原表中取出 city、name 和 age 三个字段返回给客户端。

实际上就是从sort_buffer种依次取出id,然后到原表中查到city,name和age三个字段的结果,不需要再服务端耗费内存存储结果,是直接返回客户端的。

全字段排序VSrowid排序

  • 排序内存小,影响排序效率,采用rowid排序,可以一次排序更多的行,但是需要去回原表取数据;
  • 排序内存大,优先全字段排序,直接再内存中返回查询结果;

MySQL设计思想:如果内存足够,就要多利用内存,尽量减少磁盘的访问;
对于InnoDB表来说,rowid排序会要求回表多造成磁盘读,不会被优先选择。

并不是所有的order by语句都需要排序操作,MySQL之所以要生成临时表,并且在临时表上做排序操作,原因是因为数据都是无序的

如果从city这个索引取出来的行,天然都是按照name递增排序的话,查询过程如下;

在市民表上创建city和name的联合索引,对应的SQL语句如下:

alter table t add index city_user(city,name);

查询过程:

  1. 从索引(city,name)找到第一个满足city=‘上海’ 条件的主键id;
  2. 到主键id中取出整行,取name、city、age三个字段的值,作为结果集直接返回;
  3. 从索引(city,name)取出下一个记录主键id;
  4. 重复2、3,直到查到1000个记录,或者不满足city条件的时候即可;

采用覆盖索引能够对上述查询语句在进行优化 ,覆盖索引是指索引上的信息足够满足查询要求,不需要再回到主键索引上去取数据

按照覆盖索引,创建city、name和age的联合索引,对应SQL语句如下:

alter table t add index city_user_age(city,name,age);

查询过程:

  1. 从索引(city,name,age)找到第一个满足条件city='上海’的记录,取出city,name,age三个字段的值,作为结果集的一部分返回;
  2. 重复从索引(city,name,age)取出下一个记录,同样取出三个字段的值;
  3. 重复执行步骤2,直到查到第1000条记录,或者不满足city='上海’条件时,循环结束。

总结

了解了执行orderby语句中全字段排序和rowid排序算法流程,在使用orderby语句的时候要清楚每个语句的排序逻辑的实现,分析出每个语句的执行对于系统资源的消耗。

你可能感兴趣的:(MySQL,order,by,全字段排序,rowid排序)