针对排序来说,order by 是我们使用非常频繁的关键字。结合之前我们对索引的了解再来看这篇文章会让我们深刻理解在排序的时候,是如何利用索引来达到少扫描表或者使用外部排序的。

先定义一个表辅助我们后面理解

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

这时我们写一条查询语句

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

根据上面的表定义来看,city=xxx 可以使用到我们定义的一个索引。但是 order by name 明显我们没有索引,所以肯定需要先用索引查询到 city=xxx 然后再进行回表查询,最后再排序。

全字段排序

在 city 字段上面创建索引之后,我们使用执行计划来查看这个语句

可以看到有索引的情况下 我们这里还是使用了 "Using filesort" 表示需要排序,MySQL 会给每个线程分配一块内存用于排序 称为 sort_buffer。

我们在执行上面 select 语句的时候通常经历了这样一个过程

1. 初始化 sort_buffer, 确认放入 name, city, age 这三个字段。

2. 从索引 city 找到第一个满足 city='杭州'条件的主键 id。

3. 回表取到 name, city, age 三个字段值,存入 sort_buffer 中。

4. 从索引 city 取下一个主键 id 记录。

5. 重复 3-4 步骤,直到 city 不满足条件。

6. 对 sort_buffer 中的数据按照字段 name 做快速排序。

7. 排序结果取前 1000 行返回给客户端。

这被我们称为全字段排序。

按照 name 排序这个动作即可能在内存中完成,也可以能使用外部文件排序。这取决于 sort_buffer_size 。sort_buffer_size 的默认值是 1048576 byte 也就是 1M,如果要排序的数据量小于 1m 排序就在内存中完成,如果排序数据量大,内存放不下,则使用磁盘临时文件辅助排序。

Rowid 排序

如果单行很大,需要的字段全部放进 sort_buffer 效果就不会很好。

MySQL 中专门用于控制排序的行数据长度有个参数 max_length_for_sort_data 默认是1024,如果超过了这个值就会使用 rowid 排序。那么执行上面语句的流程就变成了

1. 初始化 sort_buffe 确定放入两个字段即 name 和 id 。

2. 从索引 city 找到第一个满足 city = '杭州'条件的主键 id。

3. 回表取 name 和 id 两个字段 存入 sort_buffer 中。

4. 取下个满足条件的记录 重复 2 3 步骤。

5. 对 sort_buffer 中的 name 进行排序。

6.遍历结果取前 1000 行。然后按照 id 再回一次表取的结果字段返回给客户端。

其实并不是所有 oder by 语句都需要进行上面的二次排序操作。从上面分析的执行过程,我们可以注意到。MySQL 之所以需要生成临时表,是因为要在临时表上做排序,是因为之前我们取得的是数据是无序的。

如果我们对刚才的索引修改一下,使得他是一个联合索引,那么第二个字段我们拿到的值其实就是有序的了。

联合索引满足这么一个条件,当我们的第一个索引字段是相等的情况下,第二个字段是有序的。

这能保证如果我们建立 (city,name) 索引的话,当我们在搜索 city='杭州'的情况的是时候找到的目标第二个字段 name 其实是有序的。所以查询过程可以简化成。

1. 从索引 (city, name) 找到第一个满足 city = '杭州'条件的主键 id 。

2. 回表取到 name city age 三个值返回。

3. 取下一个 id 。

4. 重复2 3 两个步骤直到 1000 条记录,或者是不满足 city = '杭州'条件结束。

也因为查询过程都可以使用到索引的有序性,所以不再需要排序也不需要时使用 sort buffer 了。

更近一步的优化就是之前说过的索引覆盖,将需要查询的字段也覆盖进索引中,再省掉回表的步骤,可以让整个查询的速度更快。

Reference:

本读书笔记皆来自发布在极客时间的 林晓斌(丁奇)的 MySQL 实战45讲:

极客时间版权所有: https://time.geekbang.org/ 版权所有:

https://time.geekbang.org/column/article/73479

【MySQL 读书笔记】“order by”是怎么工作的?的更多相关文章

  1. 【MySQL 读书笔记】RR(REPEATABLE-READ)事务隔离详解

    这篇我觉得有点难度,我会更慢的更详细的分析一些 case . MySQL 的默认事务隔离级别和其他几个主流数据库隔离级别不同,他的事务隔离级别是 RR(REPEATABLE-READ) 其他的主流数据 ...

  2. 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动

    开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...

  3. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  4. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

  5. 【MySQL 读书笔记】当我们在使用索引的时候我们在做什么

    我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点. 因为索引是数据引擎层的结构我们只针对最常见使用的 Innodb 使用的 B+Tree 搜索树结构进行介绍. 每一个 ...

  6. 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么

    看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...

  7. 《android开发艺术探索》读书笔记(四)--View工作原理

    接上篇<android开发艺术探索>读书笔记(三) No1: View的三大流程:测量流程.布局流程.绘制流程 No2: ViewRoot对应于ViewRootImpl类,它是连接Wind ...

  8. 高性能MySQL --- 读书笔记(2) - 2016/8/2

    第1章 MySQL架构 MySQL架构与其他数据库服务器大不相同,这使它能够适应广泛的应用.MySQL足够灵活,能适应高要求架构.例如Web应用,同时还适用于嵌入式应用.数据仓库.内容索引和分发软件. ...

  9. 高性能MySQL --- 读书笔记(1) - 2016/8/2

    此书不但帮助MySQL初学者提高使用技巧,更为有经验的MySQL DBA指出了开发高性能MySQL应用的途径.全书包括14章,内容覆盖MySQL系统架构.设计应用技巧.SQL语句优化.服务器性能调优. ...

随机推荐

  1. Ubuntu18.04防火墙相关

    Ubuntu 18.04 LTS 系统中已经默认附带了 UFW 工具,如果您的系统中没有安装,可以在「终端」中执行如下命令进行安装: sudo apt install ufw 检查UFW状态 sudo ...

  2. SharePoint中用Power shell命令设置文档库列表的权限

    首先停止继承权限 $web = Get-PnPweb $spoList= Get-PnPList "Testlist" -Web $web (注释:获取对象)$spoList.Br ...

  3. 前端开发 Angular

    https://www.angularjs.net.cn/tutorial/18.html

  4. 易百教程人工智能python修正-人工智能数据准备-标记数据

    我们已经知道,某种格式的数据对于机器学习算法是必需的. 另一个重要的要求是,在将数据作为机器学习算法的输入发送之前,必须正确标记数据. 例如,如果所说的分类,那么数据上会有很多标记. 这些标记以文字, ...

  5. UML系列——OO Unit4分析和学期总结

    一.本单元的架构设计 1.类图 第一次 第二次 2.关键方法和架构简述 总体而言是读取图的时候就完成大部分计算(完成缓存),调用查询方法时只是展示计算的结果,少部分直接计算.主要是设计了各种自己定义的 ...

  6. DEDECMS标签笔记

    注意点: 1.dede的标签不可以嵌套(除了channelartlist里面可以嵌套指定的标签),那么当需要使用{dede:global.cfg_webname/}dede标签的时候我们需要转换成[f ...

  7. Part_six:Redis-cluster 实现集群

    redis-cluster 1.并发问题 redis官方生成可以达到 10万/每秒,每秒执行10万条命令 假如业务需要每秒100万的命令执行呢? 2.客户端分片 redis3.0集群采用P2P模式,完 ...

  8. AI人脸识别SDK接入 — 参数优化篇(虹软)

    引言 使用了虹软公司免费的人脸识别算法,感觉还是很不错的,当然,如果是初次接触的话会对一些接口的参数有些疑问的.这里分享一下我对一些参数的验证结果(这里以windows版本为例,linux.andro ...

  9. expect脚本远程登录、远程执行命令和脚本传参简单用法

    expect介绍: 最近想写一个自动化安装脚本,涉及到远程登录.分发文件包.远程执行命令等,其中少不了来回输入登录密码,交互式输入命令等,这样就大大降低了效率,那么有什么方法能解决呢?不妨试试expe ...

  10. QEMU简介

    参考:What Is the Difference between QEMU and KVM? 注意:上面参考文章有个错误,他把KVM算成类型一虚拟化,应该是类型2虚拟化. 关于类型一虚拟化和类型二虚 ...