为排序使用索引 OrderBy 优化|学习笔记

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 快速学习为排序使用索引 OrderBy 优化

开发者学堂课程【MySQL 高级应用 - 索引和锁为排序使用索引 OrderBy 优化】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/598/detail/8625


为排序使用索引 OrderBy 优化


目录:

一、OrderBy 关键字排序优化

二、优化策略

三、小总结

 

一、OrderBy 关键字排序优化

1MySOL 支持二种方式的排序:FileSort IndexIndex MySQL 扫描索引本身内部完成排序,所以效率会比较高。FileSort 方式效率较低,在 ORDER BY 查询中,尽量使用 Index 方式排序,避免使用 FileSort 方式排序。所以我们在使用 order by 的时候, 把 order by 查询结果由 :using filesort 优化到 using index
根据之前学过的知识,在没有办法使用 Using Index 的时候 FileSort 可以接受。其他情况尽量使用 Index 方式排序。

现举例说明:

1,建表:

CREATE TABLE tblA(

#id int primary key not null auto_increment,

Age INT,

Birth TIMESTAMP NOT NULL

);

INSERT INTO tblA(age,birth) VALUES (22,NOW());

INSERT INTO tblA(age,birth) VALUES (23,NOW());

INSERT INTO tblA(age,birth) VALUES (24,NOW());

CREATE INDEX idx_A_ageBirth ON tblA(age,birth);

SELECT * FROM tblA;

Mysql > SELECT * FROM tblA;

执行结果:

image.png

3 rows in set ( 0.00 sec)

执行完代码之后,可以看到数据库中已经产生这样的表。

建完表以后,看一下表里产生的 keys

注意:现在我们对索引的分析,不再是 WHERE 之后,ORDER BY 之前的字段。
a:输入代码:

mysql > explain SELECT * FROM tblA where age>20 order by age;

重点关注一下:看一下 ORDER BY 之后会不会产生 FileSort

image.png

1 row in set (0.01 sec)

可以看到此次执行之后,并没有产生 Filesort

b:输入代码:

mysql > EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY age, birth;

运行结果:

image.png

运行得到了跟例子 a 同样的结果。

c

输入代码:mysql > explain SELECT * FROM tblA where age>20 order by birth;

运行结果:

image.png

1 row in set (0.00 sec)

此时产生了 Using FileSort

简单总结:

a,例 b,例 c 不同的地方就是例a,b查询的时候,order by 查询的第一个字段是 age ,而例 c 查询的时候第一个字段则是 birth

所以,索引的作用就是排序跟查询,如果建立索引的时候的字段跟 order by 查询的字段顺序一样,那么就不会产生 Using filesort

d
输入代码:
mysql > EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY birth,age;

运行结果:

image.png

可以看到,在例 d 中,order by 的顺序跟建立索引的顺序不同,此时产生了 Using Filesort 重新排序。

e :输入代码:

Mysql > EXPLAIN SELECT * FROM tblA ORDER BY birth;

运行结果:

image.png

此时也使用了 Filesort

f ,输入代码:

Mysql > EXPLAIN SELECT * FROM tblA WHERE birth > ‘2016-01-28 00:00:00’ ORDER BY birth;

运行结果:

image.png

此时,也使用了 Filesort

g,输入代码:

Mysql > EXPLAIN SELECT * FROM tblA WHERE birth > ‘2016-01-28 00:00:00’ORDER BY age;

运行结果:

image.png

此时没有使用 Filesort

h,输入代码:

Mysql > EXPLAIN SELECT * FROM tblA ORDER BY age ASC, birth DESC;

运行结果:

image.png

可以看到,尽管查询的顺序,查询的字段都是 agebirth,但是此次查询还是产生了 Filesort 。原因在于:ORDER BY 默认是升序,而此次查询 age 使用了 ASC,而 birth 使用了 DESC。此时,Index索引并没有使用上,所以 Mysql 只能使用 Filesort

总结:

image.png

ORDER BY 满足两种情况,会使用 Index 排序:

ORDER BY 语句使用索引最左前列;

使用 Where 子句与 Order By 子句条件列组合满足索引最左前列。

尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀。

此时只能使用 SQL 数据库服务器的参数调优,这是数据库优化的最后一招。

如果不在索引列上,如:例 hmysql 就要启动双路排序和单路排序。
双路排序

Mysql4.1 之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,读取行指针和 orderby 列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值从列表中读取对应的数据输出。取一批数据,就要对磁盘进行两次扫描,众所周知,I\O 非常耗时;所以在 mysql4 之后,出现了第二种改进的算法,就是单路排序;
单路排序

从磁盘读取查询需要的所有列,按照 orderby 列在 buffer 对它们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。并且把随机 IO 变成了顺序 IO 但是它会使用更多的空间,因为它把每一行都保存在内存中了。

结论及引申出的问题

由于单路是后出的,总体而言好过双路

但是用单路有问题:如果数据一次性能抓取完,就用单路排序,如果数据不能一次性抓取,就会出现多路排序,性能反而不如双路,就比较麻烦。例如:

sort_buffer 中,方法 B 比方法 A 要多占用很多空间,因为方法 B  是把所有字段都取出,所以有可能取出的数据的总大小超出了 sort_bufer 的容量,导致每次只能取 sort_buffer 容量大小的数据,进行排序(创建 tmp 文件,多路合并),排完再取 sort buffer 容量大小,再排……从而导致了多次 I\O 。本来想省一次 I\O 操作,反而导致了大量的 I\O 操作,反而得不偿失。

 

二、优化策略

1、增大 sort_buffer_size 参数的设置

2、增大 max_length_for_sort_data 参数的设置

3、提高 Order By 的速度

1. Order by select*是一个大忌只 Query 需要的字段,这点非常重要。在这里的影响是:

1.1 Query 的字段大小总和小于 max_length_for_sort_data 而且排序字段不是 TEXT|BLOB 类型时,会用改进后的算法——单路排序,否则用老算法一一多路排序。

1.2两种算法的数据都有可能超出 sort buffer 的容量,超出之后,会创建 tmp 文件进行合并排序,导致多次 O ,但是用 单路排序算法的风险会更大一些所以要提高 sort_buffer_size

尝试提高 sort_buffer_ size

不管用哪种算法,提髙这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的

3.尝试提高max_length_for_sort_data

提高这个参数,会增加用改进算法的概率。但是如果设的太高,数据总容量超出sort_buffer_size的概率就增大,明显症状是高的磁盘 ⅣO 活动和低的处理器使用率


三、索引跟 order by 的小总结为排序使用索引

Mysql 两种排序方式: 文件排序或扫描有序索引排序

Mysql 能为排序与查询使用相同的索引

KEY a_b_c(a, b, c)

order by 能使用索引最左前缀

-ORDER BY a

-ORDER BY ab

-ORDERBY abc

-ORDER BY a DESCb DESCc DESC

如果 WHERE 使用素引的最左前缀定义为常量,则 orderby 能使用素引

-WHERE a=const ORDER BY bc

-WHERE a = const AND b = const ORDER BY c

-WHERE a = const ORDER BY b, c

-WHERE a = const AND b > const ORDER BY b, c

不能使用索引进行排序

-ORDER BY a ASC b DESC, c DESC /*

排序不一致*/

-WHERE g = const ORDER BY b, c /*

丢失 a 索引*/

-WHERE a = const ORDER BY c /*

丢失 b 索引*/

-WHERE a = const ORDER BY a, d /*

不是素引的一部分*

-WHERE a in (…) ORDER BY b, c /*

对于排序来说,多个相等条件也是范围查询*/

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
关系型数据库 MySQL 索引
MySQL基础-排序查询(下)
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数 ;
374 0
|
SQL 关系型数据库 MySQL
使用索引消除group by 排序
ySQL数据库在使用group by查询时默认会进行排序,有时候我们并不需要这种排序,消除这种排序有两种方式,本文介绍其中一种,即使用索引消除排序,这种方式还有一个附加的好处,就是避免临时表的创建。
662 0
|
SQL
ORDER BY:对查询结果进行排序
ORDER BY:对查询结果进行排序
105 0
|
SQL 数据库
对查询结果进行排序
对查询结果进行排序
88 0
|
关系型数据库 MySQL 数据库
MySQL基础-排序查询(上)
排序在日常开发中是非常常见的一个操作,有升序排序,也有降序排序。
142 0
|
关系型数据库 MySQL 数据库
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询
127 0
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询
|
关系型数据库 MySQL 数据库
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询2
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询
111 0
MySQL数据库基础学习Day2:条件查询,排序、限制和去重操作,聚合查询,分组查询2
|
关系型数据库 MySQL 数据库
使用order by对查询结果排序|学习笔记
快速学习使用order by对查询结果排序
170 0
|
算法 搜索推荐 关系型数据库
Orderby 排序优化
在日常的业务开发中,order by 排序是少不了的。但要写出高效的排序SQL,需要先花点精力和时间来了解排序的底层原理,这样才能找到优化排序的好策略。
1302 0
Orderby 排序优化