MySQL查询优化之十-ORDER BY优化(ORDER BY Optimization)


如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

环境:
MySQL版本:5.5.15
操作系统:windows

本文讨论ORDER BY优化(ORDER BY Optimization)。

本文介绍MySQL何时可以使用索引来满足ORDER BY子句,当不能使用索引时使用的文件排列算法,以及优化器中有关ORDER BY的执行计划信息。

主要内容:

  • 使用索引满足ORDER BY
  • 使用filesort优化
  • 原始filesort算法
  • 修改后的filesort算法
  • filesort算法的比较
  • 影响ORDER BY优化
  • ORDER BY执行计划信息可用

1.使用索引满足ORDER BY

在某些情况下,MySQL可以使用索引来满足ORDER BY子句,而无需执行额外的排序。

只要所有未使用的索引部分和所有额外的ORDER BY列都是WHERE子句中的常量,即使ORDER BY与索引完全不匹配,也可以使用索引。 以下查询使用索引来解决ORDER BY部分:

SELECT * FROM t1ORDER BY key_part1, key_part2;SELECT * FROM t1WHERE key_part1 = constantORDER BY key_part2;SELECT * FROM t1ORDER BY key_part1 DESC, key_part2 DESC;SELECT * FROM t1WHERE key_part1 = 1ORDER BY key_part1 DESC, key_part2 DESC;SELECT * FROM t1WHERE key_part1 > constantORDER BY key_part1 ASC;SELECT * FROM t1WHERE key_part1 < constantORDER BY key_part1 DESC;SELECT * FROM t1WHERE key_part1 = constant1 AND key_part2 > constant2ORDER BY key_part2;

在某些情况下,MySQL不能使用索引来解析ORDER BY,尽管它仍然可以使用索引来查找匹配WHERE子句的行。 例子:

  • 查询在不同的索引上使用ORDER BY:
SELECT * FROM t1 ORDER BY key1, key2;
  • 查询在索引的不连续部分使用ORDER BY:
SELECT * FROM t1 WHERE key2=constant ORDER BY key_part1, key_part3;
  • 查询混合了ASC和DESC:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
  • 用于读取行的索引与ORDER BY中使用的索引不同:
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
  • 查询使用ORDER BY的表达式,该表达式包含索引列名称以外的其他术语:
SELECT * FROM t1 ORDER BY ABS(key);
SELECT * FROM t1 ORDER BY -key;
  • 查询连接多个表,并且ORDER BY中的列不是全部来自用于检索行的第一个非常数表。 (这是EXPLAIN输出中没有常量联接类型的第一个表。)
  • 该查询具有不同的ORDER BY和GROUP BY表达式。
  • 只有ORDER BY子句中指定的列的前缀有一个索引。 在这种情况下,索引不能用于完全解决排序顺序。 例如,如果仅对CHAR(20)列的前10个字节进行索引,则索引无法区分超过第10个字节的值并需要一个文件夹。
  • 索引不按顺序存储行。 例如,对于MEMORY表中的HASH索引,这是正确的。

用于排序的索引的可用性可能受到使用列别名的影响。 假设列t1.a被索引。 在这个语句中,选择列表中的列名是a。 它引用t1.a,就像在ORDER BY中引用a一样,所以可以使用t1.a上的索引:

SELECT a FROM t1 ORDER BY a;

在此语句中,选择列表中列的名称也是a,但它是别名。 它引用ABS(a),就像在ORDER BY中引用a一样,所以t1.a上的索引不能被使用:

SELECT ABS(a) AS a FROM t1 ORDER BY a;

在以下语句中,ORDER BY引用的名称不是选择列表中列的名称。 但是在t1中有一列名为a,所以ORDER BY引用t1.a并且可以使用t1.a上的索引。 (当然,得到的排序顺序可能与ABS(a)的顺序完全不同。)

SELECT ABS(a) AS b FROM t1 ORDER BY a;

默认情况下,MySQL对所有GROUP BY col1,col2,…查询进行排序,就像您在查询中指定了ORDER BY col1,col2 …一样。 如果你包含一个包含相同列列表的明确的ORDER BY子句,MySQL会优化它,而不会有任何速度损失,尽管排序仍然存在。
如果查询包含GROUP BY,但您希望避免排序结果的开销,则可以通过指定ORDER BY NULL来禁止排序。 例如:

INSERT INTO foo
SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL;

优化器仍然可以选择使用排序来实现分组操作。 ORDER BY NULL会禁止对结果进行排序,而不是通过分组操作来完成排序以确定结果。

注意:
默认情况下GROUP BY默认排序(也就是说,在没有ASC或DESC标识符的情况下),但不建议使用隐式GROUP BY排序。 要生成给定的排序顺序,请为GROUP BY列使用显式的ASC或DESC指示符,或者提供ORDER BY子句。 GROUP BY排序是一个MySQL扩展,可能会在未来版本中更改; 例如,可以让优化器以任何它认为最有效的方式排序分组,并避免排序开销。

2.使用filesort优化

MySQL有多种文件排序算法用于排序和检索结果。 原始算法只使用ORDER BY列。 修改的算法不仅使用ORDER BY列,而且使用查询引用的所有列。

优化器选择要使用的文件流算法。 除了涉及BLOB或TEXT列时,它通常使用修改的算法,在这种情况下,它使用原始算法。 对于每种算法,排序缓冲区大小都是sort_buffer_size系统变量值。

3.原始filesort算法

原始的filesort算法工作如下:
1) 根据键或表格扫描读取所有行。 跳过与WHERE子句不匹配的行。
2) 对于每一行,在排序缓冲区中存储由一对值(排序键值和行ID)组成的元组。
3) 如果所有对都适合排序缓冲区,则不会创建临时文件。 否则,当排序缓冲区变满时,在内存中对其执行快速排序并将其写入临时文件。 保存一个指向已排序块的指针。
4) 重复前面的步骤,直到读取所有行。
5) 将MERGEBUFF(7)区域多合并到另一个临时文件中的一个块。 重复,直到第一个文件中的所有块都在第二个文件中。
6) 重复以下操作,直到MERGEBUFF2(15)块的数量少于左侧。
7) 在最后的多重合并中,只有行ID(值对的最后一部分)被写入结果文件。
8) 使用结果文件中的行ID按排序顺序读取行。 为了优化这一点,请读入一大块行ID,对它们进行排序,然后使用它们按排序顺序将行读入行缓冲区。 行缓冲区大小是read_rnd_buffer_size系统变量值。 此步骤的代码位于sql / records.cc源文件中。

这种方法的一个问题是它读取两次行:一次在WHERE子句评估过程中,以及在对值对进行排序之后。 即使第一次连续访问这些行(例如,如果进行了表扫描),也是第二次随机访问这些行。 (排序键是有序的,但行位置不是。)

4.修改后的filesort算法

修改后的filesort算法包含一个优化,以避免两次读取行:它记录排序键值,但不是行ID,而是记录查询引用的列。 修改后的filesort算法如下所示:
1) 读取与WHERE子句匹配的行。
2) 对于每一行,在排序缓冲区中存储由排序键值和查询引用的列组成的元组。
3) 当排序缓冲区变满时,通过内存中的排序键值对元组进行排序,并将其写入临时文件。
4) 合并排序临时文件后,按排序顺序检索行,但直接从已排序的元组中读取查询所需的列,而不是再次访问表。

修改后的filesort算法使用的元组长度比原始算法使用的长度更长,并且排序缓冲区中的元素更少。 因此,额外的I / O可以使修改的方法变得更慢,而不是更快。 为避免减速,只有在排序元组中额外列的总大小不超过max_length_for_sort_data系统变量的值时,优化程序才会使用修改的算法。 (将此变量的值设置得太高的一个症状是高磁盘活动和低CPU活动的组合。)

5.filesort算法的比较

假设一个表t1有四个VARCHAR列a,b,c和d,并且优化器使用这个查询的filesort:

SELECT * FROM t1 ORDER BY a, b;

查询按a和b排序,但返回所有列,所以查询引用的列是a,b,c和d。 根据优化器选择哪种文件排列算法,查询执行如下:

对于原始算法,排序缓冲区元组具有以下内容:

(fixed size a value, fixed size b value,
row ID into t1)

优化器对固定大小的值进行排序。 排序后,优化器按顺序读取元组,并使用每个元组中的行ID从t1读取行以获取选择列表列值。

对于修改的算法,排序缓冲区元组具有以下内容:

(fixed size a value, fixed size b value,
a value, b value, c value, d value)

优化器对固定大小的值进行排序。 排序后,优化器按顺序读取元组,并使用a,b,c和d的值来获取选择列表值,而不再读取t1。

6.影响ORDER BY优化

对于未使用filesort的慢ORDER BY查询,请尝试将max_length_for_sort_data降至适合触发文件夹的值。

要提高ORDER BY速度,请检查您是否可以让MySQL使用索引而不是额外的分类阶段。 如果这不可行,您可以尝试以下策略:

  • 增加sort_buffer_size变量值。 理想情况下,值应该足够大,以便整个结果集适合排序缓冲区(以避免写入磁盘和合并过程),但最小值必须足够大以容纳15个元组。

考虑到排序缓冲区中存储的列值大小受max_sort_length系统变量值影响。 例如,如果元组存储了长字符串列的值,并增加了max_sort_length的值,排序缓冲区元组的大小也会增加,并且可能需要您增加sort_buffer_size。 对于由字符串表达式计算的列值(如调用字符串值函数的结果),filesort算法不能指示表达式值的最大长度,因此它必须为每个元组分配max_sort_length字节。

要监视合并通道的数量,请检查Sort_merge_passes状态变量。

  • 增加read_rnd_buffer_size变量值。

  • 通过声明列的大小,每列使用更少的RAM,因为它们需要保存存储在其中的值。 例如,如果值不超过16个字符,则CHAR(16)优于CHAR(200)。

  • 将tmpdir系统变量更改为指向具有大量可用空间的专用文件系统。 变量值可以列出以循环方式使用的多个路径; 您可以使用此功能将负载分散到多个目录中。 用Unix上的冒号字符(:)和Windows上的分号字符(;)分隔路径。 路径应为位于不同物理磁盘上的文件系统中的目录命名,而不是同一磁盘上的不同分区中的目录。

7.ORDER BY执行计划信息可用

使用EXPLAIN SELECT … ORDER BY,您可以检查MySQL是否可以使用索引来解析查询。 如果您在Extra列中看到使用filesort,则不能这样做。 Filesort使用类似于MEMORY存储引擎所使用的固定长度的行存储格式。 可变长度类型(如VARCHAR)使用固定长度进行存储。

如果文件已完成,EXPLAIN输出包括在Extra列中使用filesort。

具有和不具有LIMIT的ORDER BY可以以不同顺序返回行。


Reference:
https://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html


觉得文章对你有帮助,可以用微信扫描二维码捐赠给博主,谢谢!

如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

MySQL查询优化之十-ORDER BY优化(ORDER BY Optimization)相关推荐

  1. MYSQL查询优化器

    MYSQL 逻辑结构 MySQL 使用典型的客户端/服务器(Client/Server)结构, 体系结构大体可以分为三层:客户端.服务器层以及存储引擎层.其中,服务器层又包括了连接管理.查询缓存 .S ...

  2. mysql中order by优化的那些事儿

    为了测试方便和直观,我们需要先创建一张测试表并插入一些数据: CREATE TABLE `shop` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '记 ...

  3. mysql key value 排序_MySQL利用索引优化ORDER BY排序语句的方法

    创建表&创建索引 create table tbl1 ( id int unique, sname varchar(50), index tbl1_index_sname(sname desc ...

  4. MySQL如何利用索引优化ORDER BY排序语句

    MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通 ...

  5. Mysql优化(三):优化order by

    MySQL中的两种排序方式 .通过有序索引顺序扫描直接返回有序数据 因为索引的结构是B+树,索引中的数据是按照一定顺序进行排列的,所以在排序查询中如果能利用索引,就能避免额外的排序操作.EXPLAIN ...

  6. mysql order by 索引名字_MySQL如何利用索引优化ORDER BY排序语句

    MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通 ...

  7. MySQL 优化 —— ORDER BY 优化

    引言 本文翻译自MySQL 官网:ORDER BY Optimization,MySQL 版本:5.7. 这一部分描述了MySQL何时会使用索引来满足order by子句,filesort 操作会在索 ...

  8. 40-400-044-运维-优化-MySQL order by 优化

    文章目录 1.概述 2.MySQL中的两种排序方式 3.ORDER BY优化的核心原则 4.ORDER BY优化实战 ORDER BY优化 WHERE + ORDER BY 优化 Filesort优化 ...

  9. mysql order by 语句_Mysql优化order by语句的方法详解

    本篇文章我们将了解ORDER BY语句的优化,在此之前,你需要对索引有基本的了解,不了解的老少爷们可以先看一下我之前写过的索引相关文章.现在让我们开始吧. MySQL中的两种排序方式 1.通过有序索引 ...

最新文章

  1. c#实例-子线程查找另一线程模态对话框句柄(invoke测试)
  2. 关于PHP代码写的下载文件打不开的问题,自己备忘!(韩老师2011年的例子)
  3. T-sql语句查询执行顺序
  4. 数据驱动的智慧城市 中兴通讯推进“沈阳模式”落地
  5. RTKLIB中的卫星天线与接收机天线修正
  6. RCWL-0516微波雷达感应开关
  7. 嵌入式软件工程师工作经验分享
  8. Java程序员开发必备软件-Windows版
  9. Java实现批量下载《神秘的程序员》漫画
  10. FineReport10 决策报表常用javascript脚本
  11. 速度测试(speed test)
  12. 远程VPS和本地电脑之间无法粘贴复制及分享文件
  13. vue2 typescript 项目 如何引入antd -ui组件
  14. 微信小程序iBeacon获取问题(wx.onBeaconUpdate不执行)【已解决】
  15. ANSYS中Beam188\Beam189单元命令流提取最大应力
  16. 线性系统粗浅认识——第五次作业
  17. 【Jenkins】Linux环境Jenkins下载与安装
  18. 【熬夜猛肝万字博文】学妹问我怎么入门 Javascript,百般盘问下我终于决定贡献出自己的 JavaScript入门笔记(三)
  19. html5 ios keychain,iOS 用keychain钥匙串保存账号、设备UUID及APP间共享
  20. 【软件之道】Origin2017-安装及破解方法

热门文章

  1. COVER + THE BOY WHO LIVED
  2. ArcGIS之基于GIS的旅游辐射区人口统计
  3. 步进电机的启动频率和空载启动频率
  4. Hadoop入门学习笔记-第五天(hadoop-hive安装部署与配置笔记)
  5. ogre3d计算缘分的程序
  6. 目标检测YOLO实战应用案例100讲-基于边缘计算和联邦学习的矿山目标检测
  7. 什么是FPGA,PAL,EPLD?
  8. 行列式的基础知识整理
  9. MBE 语音编码模型:
  10. mysql latin1编码_mysql的latin1编码支持中文吗?