MySQL Order By索引优化方法

所属分类: Mysql / 数据库 阅读数: 1918
收藏 0 赞 0 分享
尽管 ORDER BY 不是和索引的顺序准确匹配,索引还是可以被用到,只要不用的索引部分和所有的额外的 ORDER BY 字段在 WHERE 子句中都被包括了。

使用索引的MySQL Order By
下列的几个查询都会使用索引来解决 ORDER BY 或 GROUP BY 部分:
复制代码 代码如下:

SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2;
SELECT * FROM t1 WHERE key_part1=constant GROUP BY key_part2;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;

不使用索引的MySQL Order By
在另一些情况下,MySQL无法使用索引来满足 ORDER BY,尽管它会使用索引来找到记录来匹配 WHERE 子句。这些情况如下:
* 对不同的索引键做 ORDER BY :
SELECT * FROM t1 ORDER BY key1, key2;
* 在非连续的索引键部分上做 ORDER BY:
SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
* 同时使用了 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 中的字段都不全是来自第一个非常数的表中(也就是说,在 EXPLAIN 分析的结果中的第一个表的连接类型不是 const)。
* 使用了不同的 ORDER BY 和 GROUP BY 表达式。
* 表索引中的记录不是按序存储。例如,HASH 和 HEAP 表就是这样。

通过执行 EXPLAIN SELECT ... ORDER BY,就知道MySQL是否在查询中使用了索引。如果 Extra 字段的值是 Using filesort,则说明MySQL无法使用索引。详情请看"7.2.1 EXPLAIN Syntax (Get Information About a SELECT)"。当必须对结果进行排序时,MySQL 4.1以前 它使用了以下 filesort 算法:
复制代码 代码如下:

1. 根据索引键读取记录,或者扫描数据表。那些无法匹配 WHERE 分句的记录都会被略过。
2. 在缓冲中每条记录都用一个‘对'存储了2个值(索引键及记录指针)。缓冲的大小依据系统变量 sort_buffer_size 的值而定。
3. 当缓冲慢了时,就运行 qsort(快速排序)并将结果存储在临时文件中。将存储的块指针保存起来(如果所有的‘对'值都能保存在缓冲中,就无需创建临时文件了)。
4. 执行上面的操作,直到所有的记录都读取出来了。
5. 做一次多重合并,将多达 MERGEBUFF(7)个区域的块保存在另一个临时文件中。重复这个操作,直到所有在第一个文件的块都放到第二个文件了。
6. 重复以上操作,直到剩余的块数量小于 MERGEBUFF2 (15)。
7. 在最后一次多重合并时,只有记录的指针(排序索引键的最后部分)写到结果文件中去。
8. 通过读取结果文件中的记录指针来按序读取记录。想要优化这个操作,MySQL将记录指针读取放到一个大的块里,并且使用它来按序读取记录,将记录放到缓冲中。缓冲的大小由系统变量 read_rnd_buffer_size 的值而定。这个步骤的代码在源文件 `sql/records.cc' 中。


这个逼近算法的一个问题是,数据库读取了2次记录:一次是估算 WHERE 分句时,第二次是排序时。尽管第一次都成功读取记录了(例如,做了一次全表扫描),第二次是随机的读取(索引键已经排好序了,但是记录并没有)。在MySQL 4.1 及更新版本中,filesort 优化算法用于记录中不只包括索引键值和记录的位置,还包括查询中要求的字段。这么做避免了需要2次读取记录。改进的 filesort 算法做法大致如下:
1. 跟以前一样,读取匹配 WHERE 分句的记录。
2. 相对于每个记录,都记录了一个对应的;‘元组'信息信息,包括索引键值、记录位置、以及查询中所需要的所有字段。
3. 根据索引键对‘元组'信息进行排序。
4. 按序读取记录,不过是从已经排序过的‘元组'列表中读取记录,而非从数据表中再读取一次。

使用改进后的 filesort 算法相比原来的,‘元组'比‘对'需要占用更长的空间,它们很少正好适合放在排序缓冲中(缓冲的大小是由 sort_buffer_size 的值决定的)。因此,这就可能需要有更多的I/O操作,导致改进的算法更慢。为了避免使之变慢,这种优化方法只用于排序‘元组'中额外的字段的大小总和超过系统变量 max_length_for_sort_data 的情况(这个变量的值设置太高的一个表象就是高磁盘负载低CPU负载)。想要提高 ORDER BY 的速度,首先要看MySQL能否使用索引而非额外的排序过程。如果不能使用索引,可以试着遵循以下策略:
* 增加 sort_buffer_size 的值。
* 增加 read_rnd_buffer_size 的值。
* 修改 tmpdir,让它指向一个有很多剩余空间的专用文件系统。
如果使用MySQL 4.1或更新,这个选项允许有多个路径用循环的格式。各个路径之间在 Unix 上用冒号(':')分隔开来,在 Windows,NetWare以及OS/2 上用分号(';')。可以利用这个特性将负载平均分摊给几个目录。注意:这些路径必须是分布在不同物理磁盘上的目录,而非在同一个物理磁盘上的不同目录。
更多精彩内容其他人还在看

详解windows下mysql的主从同步

半路出家到Java,刚开始听说到说程序支持读写分离感觉特别高大上,也一直没接触偶然的机会接触到了,就一定得记下来。今天先讲讲数据库的主从同步,两个好处: 是读写分离可以用上。比如 写操作就写到主数据库,读就从从数据库读取 是纯粹给数据库备份,以防硬盘彻底崩了主从数据库操作准备... 查看详情
收藏 0 赞 0 分享

SQL Server 数据库的备份详细介绍及注意事项

SQL Server 备份前言为什么要备份?理由很简单——为了还原/恢复。当然,如果不备份,还可以通过磁盘恢复来找回丢失的文件,不过SQL Server很生气,后果很严重。到时候你就知道为什么先叫你备份一次再开始看文章了。∩__∩。本系列将介绍SQL Server所有可用的备份还... 查看详情
收藏 0 赞 0 分享

SQL Server COALESCE函数详解及实例

SQL Server COALESCE函数详解很多人知道ISNULL函数,但是很少人知道Coalesce函数,人们会无意中使用到Coalesce函数,并且发现它比ISNULL更加强大,其实到目前为止,这个函数的确非常有用,本文主要讲解其中的一些基本使用:  首... 查看详情
收藏 0 赞 0 分享

windows 10 下安装mysql 5.7.17的简单笔记

之前一直在Linux下用MySQL,安装也很简单,今天试一下windows下安装,发现还真有坑。还好搞定了,把安装过程记录一下。1.  首先我们得去mysql官网下载我们需要的资源,选择Downloads—>Community,这时候就能看到MySQL Commu... 查看详情
收藏 0 赞 0 分享

mysql 5.7.17 安装配置方法图文教程(CentOS7)

CentOS7安装mysql笔记1 CentOS7默认安装mariadb数据库,卸载mariadb。rpm -qa|grep mariadbyum remove mariadb-libs.x86_642 配置YUM源 1)下载mysql源安装包wget http://xiazai... 查看详情
收藏 0 赞 0 分享

Mysql 行级锁的使用及死锁的预防方案

一、前言    mysql的InnoDB,支持事务和行级锁,可以使用行锁来处理用户提现等业务。使用mysql锁的时候有时候会出现死锁,要做好死锁的预防。二、MySQL行级锁    行级锁又分共享锁和排他锁。    共享锁:      名词解释:共享锁又叫做读锁,所有的事务只能对其... 查看详情
收藏 0 赞 0 分享

远程连接mysql错误代码1130的解决方法

下面给大家介绍远程连接mysql错误代码1130的解决方法:以上所述是小编给大家介绍的远程连接mysql错误代码1130的解决方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!... 查看详情
收藏 0 赞 0 分享

Windows下MySQL 5.7无法启动的解决方法

问题描述:从网上下了5.7 的MySQL,在bin目录下执行 start mysqld ,弹出个cmd窗口一闪就没了,也看不清是什么报错。mysqld --install安装了服务,也启动不了。处理步骤:1、打开事件查看器检查报错信息2、网上查了,都说如果是 linux 需要执行... 查看详情
收藏 0 赞 0 分享

mysql批量更新多条记录的同一个字段为不同值的方法

首先mysql更新数据的某个字段,一般这样写:UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value';也可以这样用in指定要更新的记录:UPDATE mytable SET myfield = ... 查看详情
收藏 0 赞 0 分享

在Linux环境下mysql的root密码忘记解决方法(三种)

MySQL密码的恢复方法之一1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库。 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态下,其他的用户也可以任意地登录和修改MySQL的信息。可以采用将MySQL对外的端... 查看详情
收藏 0 赞 0 分享
查看更多