MySQL教程:Order By索引优化

2016-02-19 15:28 5 1 收藏

下面请跟着图老师小编一起来了解下MySQL教程:Order By索引优化,精心挑选的内容希望大家喜欢,不要忘记点个赞哦!

【 tulaoshi.com - 编程语言 】

  在一些情况下,MySQL可以直接使用索引来满足一个 ORDER BY 或 GROUP BY 子句而无需做额外的排序。尽管 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;

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  * 在非连续的索引键部分上做 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. 按序读取记录,不过是从已经排序过的‘元组’列表中读取记录,而非从数据表中再读取一次。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  使用改进后的 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 上用分号(';')。可以利用这个特性将负载平均分摊给几个目录。注意:这些路径必须是分布在不同物理磁盘上的目录,而非在同一个物理磁盘上的不同目录

来源:http://www.tulaoshi.com/n/20160219/1609699.html

延伸阅读
问题描述: 我们要访问的表是一个非常大的表,四千万条记录,id是主键,program_id上建了索引。 执行一条SQL: select * from program_access_log where program_id between 1 and 4000 这条SQL非常慢。 我们原以为处理记录太多的原因,所以加了id限制,一次只读五十万条记录 select * from program_access_l...
标签: Web开发
  本文主要讲述了如何加速动态网站的MySQL索引分析和优化。 iSH中国教程在线 一、什么是索引? iSH中国教程在线 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就...
标签: MySQL mysql数据库
一、什么是索引? 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的...
下面将通过实例分析两种排序实现方式及实现图解: 假设有 Table A 和 B 两个表结构分别如下: 1 sky@localhost : example 01:48:21 show create table AG 2 3 *************************** 1. row *************************** 4 5 Table: A 6 7 Create Table: CREATE TABLE `A` ( 8 9 `c1` int(11) ...
SELECT TOP 50 ROW_NUMBER() OVER(ORDER BY ResumeCreateTime DESC) as [RowID] ,[TopDegree] ,[DegreeRankID] ,[UserResume].[UserResumeID] ,[UserResume].[UserID] ,[ResumeName] ,[BirthDate] ,[WorkStartedDate] ,[SalaryNeeded] ,[BufferTimeSpanID] ,[ResumeCreateTime] FROM [dbo].[UserResume] INNER JOIN [dbo].[WorkExperience] ON ...

经验教程

110

收藏

50
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部