美文网首页技术分享
你的Order By执行起来为什么这么这么慢

你的Order By执行起来为什么这么这么慢

作者: 三不猴子 | 来源:发表于2020-08-25 23:07 被阅读0次

MySQL order by 执行流程

在工作中使用order by再平常不过了,但是对于mysql order 的执行流程有了解多少?

举个栗子🌰,假设我们有一张表

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL, `name` varchar(16) NOT NULL, `age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL, PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;

然后执行了一个

select city,name,age from t where city='杭州' order by name limit 1000;

全字段扫描

我们用explain命令看看这个语句的执行情况

image-20200825215034723

Extra这个字段中的“Using filesort”表示的就是需要排序,“Using filesort”表示使用索引。MySQL会给每一个线程一个叫“sort_buffer”的内存用来排序。

就上面的sql语句执行流程简单概括就是

  1. 初始化 sort_buffer,确定select的字段。
  2. 从索引中找到所有满足条件的列,在主键中获取整行,取出select的字段,放入sort buffer。
  3. 对sort buffer中的内容进行排序(上面的sql是根据name排序,这个排序动作是在内存中完成的)。
  4. 取出limit的行数返回给前端。

⚠️注意 这里是把所有满足条件的值放进sort buffer中。

由于是把全部的值放进sort buffer中,sort buffer是内存所以不一定放的下,所以就存在sort buffer放不下的情况。sort_buffer_size可以设置sort buffer的大小,如果sort buffer中放不下的话,MySQL就需要借助临时文件来处理,可以通过如下sql来确定是否使用了临时文件:

/* 打开optimizer_trace,只对本线程有效 */ 
SET optimizer_trace='enabled=on';
/* @a保存Innodb_rows_read的初始值 */
select VARIABLE_VALUE into @a from performance_schema.session_status where variable_name = 'Innodb_rows_read'
/* 执行语句 */
select city, name,age from t where city='杭州' order by name limit 1000;
/* 查看 OPTIMIZER_TRACE 输出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G
/* @b保存Innodb_rows_read的当前值 */
select VARIABLE_VALUE into @b from performance_schema.session_status where variable_name = 'Innodb_rows_read';
/* 计算Innodb_rows_read差值 */ 
select @b-@a;

这个方法是通过查看 OPTIMIZER_TRACE 的结果来确认的,你可以从 number_of_tmp_files中看到是否使用了临时文件。

image-20200825222615671

number_of_tmp_files表示的是,排序过程中使用的临时文件数。MySQL将需要排序的数据分成12份,每一份单独排序 后存在这些临时文件中。然后把这12个有序文件再合并成一个有序的大文件。 number_of_tmp_files就是0,表示排序可以直接在内存中完成。

rowid排序

在上面的全字段扫描过程中,只对原表的数据读了一遍,剩下的操作都是在sort_buffer和临时文件中执行的。但是如果select的字段非常的多的话非常占空间,sort buffer的空间又是有限的,如果就要尽量把少的字段放sort buffer,所以只有要排序的列(即name字段)和主键id,排序的结果就少了其他字段。整个执行流程如下:

  1. 初始化sort_buffer,放入需要排序的字段(name)和主键id。
  2. 找到满足where条件的列的id,在聚簇索引中拿到需要排序的字段,放入sort buffer中。
  3. 对sort buffer中的内容进行排序。
  4. 对排序后的列取出limit的行数。
  5. 根据id去聚簇索引中取出其他字段。返回给前端。

数据的排序是一个成本很高的一件事,如果这个数据本身就是有序的话那就不需要排序操作了,那怎么样才能保证本身就是有序的呢?那上面我们执行的sqlselect city,name,age from t where city='杭州' order by name limit 1000;来说的话,创建一个联合索引就可以了alter table t add index city_user(city, name); 为什么创建一个联合索引就可以?自己回忆一下联合索引的数据结构。

image-20200825224949143

可以用树搜索的方式定位到第一个满足city='杭州’的记录,并且额外确保了,接下来按顺序取“下一条记录”的遍历过程中,只要city的值是杭州,name的值就一定是有序的。执行流程就是如下:

  1. 根据索引(city,name)找到满足where条件的列
  2. 去聚簇索引取出需要的字段,返回给前端(重复limit中值的次数)

一个小思考:如果创建的是name在左city在右的联合索引一样的查询条件还能生效吗?

上面的流程如果索引中已经有了需要返回的字段就不需要去聚簇索引中取列,对于我们上面说的查询的情况我们如果创建(city,name,age)的联合索引的话就不需要再聚簇索引中获取数据了。

相关文章

  • 你的Order By执行起来为什么这么这么慢

    MySQL order by 执行流程 在工作中使用order by再平常不过了,但是对于mysql order ...

  • 为什么这么慢?

    2020年08月15日 星期六 深圳 晴 今天一直接单不停,中间喝口水的空隙赶紧帮新顾客查单,新下单的顾客还不太了...

  • 为什么这么慢?

    早上骑电动车送女儿去她爷爷家,时间赶得急,要在10分钟之内走到,所以嫌车跑得慢。 在等红绿灯时我对女儿说,今天的车...

  • 你为什么这么忙,进步还这么慢?

    来到简书,不仅认识了一帮想通过写作留下一些“痕迹”朋友,更知道了一批因写作改变了自己人生的朋友。所以,在各种信息、...

  • 孩子根本不听家长的话怎么办?教育专家:用有效沟通方法才行

    为什么会做这么慢? 这么久怎么才写这么一点儿? 你就不能认真写字吗? 讲了这么多次为什么还记不住? 怎么这么笨?就...

  • 为什么你读书这么慢?

    为什么需要耗费比别人更多的时间来阅读同一本书?为什么你总是在被别人推荐一些书你应该去阅读?似乎我跟阅读无缘了? 读...

  • 为什么你成长这么慢?

    【感悟】 成长缓慢,除了跟自身努力有关,可能还跟平台有很大关系。 这就是人们常说的,宁做凤尾不做鸡头的道理。 办公...

  • 这么慢,这么美

    最初买这本书仅因为被它的书名吸引,然而却让我有了一个难得的邂逅,欲罢不能。 这么慢,那么美。 世界愈繁,此心愈简...

  • 这么快这么慢

    突然觉得做什么事都快也不是什么好事 就像 我吃饭快所以容易长胖 我写作业快所以可能会犯错 我背书快所以容易忘 我看...

  • 为什么进展这么慢?

    从刚开始我就不断提醒自己——一定要提前做好,不能放到最后,不能磨磨唧唧的做东西,一定要逼着自己不断的向前走,不能重...

网友评论

    本文标题:你的Order By执行起来为什么这么这么慢

    本文链接:https://www.haomeiwen.com/subject/ktutsktx.html