写在前面

文章涉及到的 customer 表来源于案例库 sakila,下载地址为 http://downloads.mysql.com/docs/sakila-db.zip

MySQL 排序方式

  • 通过索引顺序扫描直接返回有序数据

  • 通过对返回数据进行排序,即 FileSort 排序。

所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。FileSort 并不代表通过磁盘文件进行排序,而只是说进行了一个排序操作,至于排序操作是否使用了磁盘文件或临时表取决于 MySQL 服务器对排序参数的设置和需要排序数据的大小。

EXPLAIN 排序分析

customer DDL

CREATE TABLE `customer` (
`customer_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`store_id` tinyint unsigned NOT NULL,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`email` varchar(50) DEFAULT NULL,
`address_id` smallint unsigned NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
`create_date` datetime NOT NULL,
`last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`customer_id`),
KEY `idx_fk_store_id` (`store_id`),
KEY `idx_fk_address_id` (`address_id`),
KEY `idx_last_name` (`last_name`),
KEY `idx_storeid_email` (`store_id`,`email`),
CONSTRAINT `fk_customer_address` FOREIGN KEY (`address_id`) REFERENCES `address` (`address_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_customer_store` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=600 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE DEFINER=`root`@`%` TRIGGER `customer_create_date` BEFORE INSERT ON `customer` FOR EACH ROW SET NEW.create_date = NOW();

返回所有用户记录,根据 customer_id 进行排序。因为 customer_id 是主键,记录都是按照主键排好序的,所以无需进行额外的排序操作,直接返回所有数据即可。

EXPLAIN SELECT * FROM customer ORDER BY customer_id;


由于默认是根据 customer_id 进行排序的,相对于上面来说,这里需要全表扫描,然后根据 store_id 对全表扫描结果进行排序,因此这里用到了 FileSort 排序。

EXPLAIN SELECT * FROM customer ORDER BY store_id;


store_id , email 这两个字段是有联合索引 idx_storeid_email 的,只查询 store_id 和 email 两个字段,直接通过联合索引所在的 B+ 树返回查询数据(该索引树先根据 store_id 字段先进行排序,然后再根据 email 字段排序好的),所以这里的查询结果就是排序好的。

EXPLAIN SELECT store_id , email FROM customer ORDER BY store_id;


和上面不同的是,排序的字段是 email,导致 FileSort 排序的原因是联合索引 idx_storeid_email 的是先根据 store_id 字段先进行排序,然后再根据 email 字段排序好的,如果直接使用 email 排序,则无法使用 idx_storeid_email 索引树排好的顺序。

EXPLAIN SELECT store_id , email FROM customer ORDER BY email;


ORDER BY 使用联合索引进行排序

EXPLAIN SELECT store_id , email FROM customer ORDER BY store_id , email;


ORDER BY 的字段混用 ASC 和 DESC 会导致使用 FileSort 排序。

EXPLAIN SELECT store_id , email FROM customer ORDER BY store_id ASC , email DESC;


固定 store_id = 1 情况下对 email 字段进行排序,使用 idx_storeid_email 索引即可

EXPLAIN SELECT store_id , email FROM customer WHERE store_id  = 1 ORDER BY email;


where 条件先进行 store_id 范围查询导致 ORDER BY email 字段无法使用 idx_storeid_email 索引进行排序。

EXPLAIN SELECT store_id , email FROM customer WHERE store_id  >= 1 AND store_id <= 3 ORDER BY email;


ORDER BY 可能出现 FileSort 的几种情况:

  1. order by 字段混用 ASC 和 DESC 排序方式。
  2. SELECT * 时,如果 order by 排序字段不是主键可能导致 FileSort。
  3. 联合索引情况下,order by 多字段排序的字段左右顺序和联合索引的字段左右顺序不一致导致 FileSort。
  4. 联合索引情况下,where 字段和 order by 字段的左右顺序和联合索引字段左右顺序或者 where 字段出现范围查询都可能导致 FileSort。

FileSort 优化

通过创建合适的索引可以减少 FileSort 的出现,但是对于某些情况下,条件限制不能让 FileSort 彻底消失,那就需要对 FileSort 进行优化。对于 FileSort,MySQL 有两种排序算法。

  • 两次扫描算法(Two Passes):首先根据条件取出排序字段和行指针,之后在排序区 sort buffer 中排序。如果排序区 sort buffer 不够,则在临时表 Temporary Table 中存储排序结果。完成排序后根据行指针回表读取完整记录。该算法是 MySQL 4.1 之前采用的算法,需要两次访问数据,第一次获取排序字段和行指针信息,第二次根据行指针获取完整记录,尤其是第二次读取操作可能导致大量随机 IO 操作;有点是排序的时候内存开销比较小。

  • 一次扫描算法(Single Passes):一次性取出满足条件的行的所有字段,然后在排序区 sort buffer 中排序后直接输出结果集。排序的时候内存开销比较大,但是排序效率比两次扫描算法要高。

MySQL 通过比较系统变量 max_length_for_sort_data 的大小和 Query 语句取出的字段总大小来判断使用哪种排序算法。如果 max_length_for_sort_data 设置足够大,那么会使用一次扫描算法;否则使用两次扫描算法。适当加大系统变量 max_length_for_sort_data 的值,能够让 MySQL 选择更加优化的 FileSort 排序算法。当然,假如 max_length_for_sort_data 设置过大,会造成 CPU 利用率过低和磁盘 IO 过高。

适当加大 sort_buffer_size 排序区,尽量让排序在内存中完成,而不是通过创建临时表放在文件中进行;当然也不能无限加大 sort_buffer_size 排序区,因为 sort_buffer_size 参数是每个线程独占的,设置过大会导致服务器 SWAP 严重,要考虑数据库活动连接数和服务器内存的大小来适当设置排序区。

尽量只使用必要的字段,SELECT 具体的字段名称,而不是 SELECT * 选择所有字段,这样可以减少排序区的使用,提高 SQL 性能。

参考

《深入浅出 MySQL 数据库开发、优化与管理维护第 2 版》

《MySQL 实战 45 讲》

最后

如果大家想要实时关注我更新的文章以及我分享的干货的话,可以关注我的公众号 我们都是小白鼠

Order by 优化的更多相关文章

  1. 8.2.1.15 ORDER BY Optimization ORDER BY 优化

    8.2.1.15 ORDER BY Optimization ORDER BY 优化 在一些情况下, MySQL 可以使用一个索引来满足一个ORDER BY 子句不需要做额外的排序 index 可以用 ...

  2. Mysql序列(七)—— order by优化

    前言 在mysql中满足order by的处理方式有两种: 让索引满足排序,即扫描有序索引然后再找到对应的行结果,这样结果即是有序: 使用索引查询出结果或者扫描表得到结果然后使用filesort排序: ...

  3. MySQL性能优化,MySQL索引优化,order by优化,explain优化

    前言 今天我们来讲讲如何优化MySQL的性能,主要从索引方面优化.下期文章讲讲MySQL慢查询日志,我们是依据慢查询日志来判断哪条SQL语句有问题,然后在进行优化,敬请期待MySQL慢查询日志篇 建表 ...

  4. Mysql查询优化汇总 order by优化例子,group by优化例子,limit优化例子,优化建议

    Mysql查询优化汇总 order by优化例子,group by优化例子,limit优化例子,优化建议 索引 索引是一种存储引擎快速查询记录的一种数据结构. 注意 MYSQL一次查询只能使用一个索引 ...

  5. mysql order by 优化 |order by 索引的应用

    在某些场景,在不做额外的排序情况下,MySQL 可以使用索引来满足 ORDER BY 子句的优化.虽然 ORDER BY并不完全精确地匹配索引,但是索引还是会被使用,只要在WHERE子句中,所有未被使 ...

  6. order by优化--Order By实现原理分析和Filesort优化

    在MySQL中的ORDER BY有两种排序实现方式: 1.利用有序索引获取有序数据 2.文件排序 在使用explain分析查询的时候,利用有序索引获取有序数据显示Using index.而文件排序显示 ...

  7. MySQL高级知识(八)——ORDER BY优化

    前言:在使用order by时,经常出现Using filesort,因此对于此类sql语句需尽力优化,使其尽量使用Using index. 0.准备 #1.创建test表. drop table i ...

  8. mysql实战优化之六:Order by优化 sql优化、索引优化

    在MySQL中的ORDER BY有两种排序实现方式: 1.利用有序索引获取有序数据 2.文件排序 在使用explain分析查询的时候,利用有序索引获取有序数据显示Using index.而文件排序显示 ...

  9. 八、ORDER BY优化

    前言:在使用order by时,经常出现Using filesort,因此对于此类sql语句需尽力优化,使其尽量使用Using index. 0.准备 #1.创建test表. drop table i ...

随机推荐

  1. USACO Training Section 1.2 [USACO1.2]方块转换 Transformations

    题目描述 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针 ...

  2. Cypress 自动化环境搭建

    1.Cypress 下载: 官网下载,下载后直接解压即可,解压后便可单机 exe 文件打开 Ps:直接打开 exe 是会报错找不到 json文件的,所以还要安装依赖环境 运行 cypress 项目前, ...

  3. C/S程序设计范式

    在socket编程之并发回射服务器3篇文章中,提到了3种设计范式: 多进程 父进程阻塞于accept调用,然后为每个连接创建一个子进程. 多线程 主线程阻塞于accept调用,然后为每个连接创建一个子 ...

  4. Java流式思想和方法引用

    目录 Java流式思想和方法引用 1. Stream流 1.1 概述 传统集合的多步遍历代码 Stream的更优写法 1.2 流式思想的概述 1.3 获取流 1.4 常用方法 ①逐一处理:forEac ...

  5. Spring官网阅读(十二)ApplicationContext详解(中)

    文章目录 1.Spring的资源(Resource) 接口简介 UML类图 抽象基类AbstractResource FileSystemResource AbstractFileResolvingR ...

  6. asp.net mvc entityframework sql server 迁移至 mysql方法以及遇到的问题

    背景: 我原来的项目是asp.net mvc5 + entityframework 6.4 for sql server(localdb,sql server),现在需要把数据库切换成mysql,理论 ...

  7. nginx脚本自动安装

    nginx脚本自动安装 脚本功能: 自动安装nginx 自动判别系统是否安装nginx 自定义安装nginx路径 自定义安装nginx版本. #!/bin/bash #2019年10月30日16:00 ...

  8. xml(4)

    schema约束 dtd语法:<!ELEMENT 元素名称 约束> schema符合xml的语法,xml语句 一个xml中可以有多个schema,多个schema用名称空间区分(类似jav ...

  9. Windows 10 IoT Core用PWM控制器控制树莓派LED灯亮度

    我接到一个需求,需要调节LED灯的亮度,且是从上位机进行控制,我了解到树莓派也有PWM,就准备通过PWM来控制灯的亮度. PWM又叫脉宽调制,是用微处理器的数字输出来对模拟电路进行控制,对模拟信号电平 ...

  10. SQL 选择列 IF表达式,Contains表达式的用法

    因为业务需要需要使用到, 列中的字段或根据列值是否满足某一条件,进行输出.比如类似与  select if()  ……from……:(但是SQL Server 没有 if 表达式) 比如,如果Scor ...