`
亚当爱上java
  • 浏览: 706027 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

MySQL如何优化ORDER BY

阅读更多
7.2.9 MySQL 如何优化 ORDER BY

在一些情况下,MySQL可以直接使用索引来满足一个 ORDER BY 或 GROUP BY 子句而无需做额外的排序。尽管 ORDER BY 不是和索引的顺序准确匹配,索引还是可以被用到,只要不用的索引部分和所有的额外的 ORDER BY 字段在 WHERE 子句中都被包括了。下列的几个查询都会使用索引来解决 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,尽管它会使用索引来找到记录来匹配 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 上用分号(';')。可以利用这个特性将负载平均分摊给几个目录。注意:这些路径必须是分布在不同物理磁盘上的目录,而非在同一个物理磁盘上的不同目录。


默认情况下,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;


7.2.10 MySQL 如何优化 LIMIT

在一些情况下,MySQL在碰到一个使用 LIMIT row_count 但没使用 HAVING 的查询时会做不同的处理:


* 如果只是用 LIMIT 来取得很少的一些记录, MySQL 有时会使用索引,但是更通常的情况是做一个全表扫描。

* 如果 LIMIT row_count 和 ORDER BY 一起使用,则MySQL在找到 row_count 条记录后就会停止排序了,而非对整个表进行排序。

* 当 LIMIT row_count 和 DISTINCT 一起联合起来时,MySQL在找到 row_count 条唯一记录后就不再搜索了。

* 在某些情况下, GROUP BY 可以通过按照顺序读取索引键来实现(或者在索引键上做排序)并且计算累计信息直到索引键改变了。在这种情况下,LIMIT row_count 不会计算任何非必须的 GROUP BY 值。

* As soon as MySQL has sent the required number of rows to the client, it aborts the query unless you are using SQL_CALC_FOUND_ROWS.

* 一旦MySQL将请求的记录全数发送给客户端后,它就中止查询除非使用了 SQL_CALC_FOUND_ROWS。

* LIMIT 0 总是返回一个空的结果集。这对于检查查询或者取得结果字段的类型非常有用。

* 当服务器使用临时表来处理查询,则 LIMIT row_count 可以用来计算需要多少空间。


7.2.11 如何避免全表扫描

如果MySQL需要做一次全表扫描来处理查询时,在 EXPLAIN 的结果中 type 字段的值是 ALL。在以下几种条件下,MySQL就会做全表扫描:


* 数据表是在太小了,做一次全表扫描比做索引键的查找来得快多了。当表的记录总数小于10且记录长度比较短时通常这么做。

* 没有合适用于 ON 或 WHERE 分句的索引字段。

* 让索引字段和常量值比较,MySQL已经计算(基于索引树)到常量覆盖了数据表的很大部分,因此做全表扫描应该会来得更快。详情请看"7.2.4 How MySQL Optimizes WHERE Clauses"。

* 通过其他字段使用了一个基数很小(很多记录匹配索引键值)的索引键。这种情况下,MySQL认为使用索引键需要大量查找,还不如全表扫描来得更快。
分享到:
评论

相关推荐

    Mysql优化order by语句的方法详解

    MySQL数据库中,ORDER BY语句用于对查询结果进行排序,其优化对于提升查询性能至关重要。在深入了解优化方法之前,理解索引的工作原理是基础。索引是数据库管理系统中用于加速查询的一种数据结构,通常采用B+树的...

    深入解析mysql中order by与group by的顺序问题

    mysql 中order by 与group by的顺序是:selectfromwheregroup byorder by注意:group by 比order by先执行,order by不会对group by 内部进行排序,如果group by后只有一条记录,那么order by 将无效。要查出group ...

    MySQL数据库优化SQL篇PPT课件.pptx

    从执行计划、SELECT语句、IN和EXIST语句、LIMIT语句、RAND函数、Order by、Group by、Distinct和Count等方面对MySQL数据库优化进行了详细的讲解。 一、执行计划 执行计划是MySQL数据库优化的重要步骤。执行计划...

    MySQL 通过索引优化含ORDER BY的语句

    MySQL数据库在处理含`ORDER BY`的SQL语句时,索引优化是非常关键的一环,因为这直接影响到查询性能。以下是一些关于如何利用索引来优化`ORDER BY`语句的知识点: 1. **合理创建索引**:索引可以显著提高数据读取...

    MySQL Order By索引优化方法

    总之,理解`ORDER BY`和`GROUP BY`的索引优化策略,以及如何通过`EXPLAIN`分析查询计划,可以帮助我们有效地优化查询,避免不必要的`filesort`操作,从而提升MySQL数据库的性能。在设计索引时,应考虑查询语句的常见...

    MySQL利用索引优化ORDER BY排序语句的方法

    创建表&创建索引 create table tbl1 ( id int unique, sname varchar(50), index tbl1_index_sname(sname desc...通过索引优化来实现MySQL的ORDER BY语句优化: 1、ORDER BY的索引优化 如果一个SQL语句形如: SELECT

    MySQL中union和order by同时使用的实现方法

    MySQL中union和order by是可以一起使用的,但是在使用中需要注意一些小问题,下面通过例子来说明。首先看下面的t1表。 1、如果直接用如下sql语句是会报错:Incorrect usage of UNION and ORDER BY。 SELECT * FROM ...

    mysql性能优化.pptx

    - 索引优化SQL:避免全表扫描,尽可能利用索引来加速查询,减少`SELECT`、`JOIN`、`ORDER BY`、`GROUP BY`操作的复杂度。 - 索引维护:定期重建和优化索引,确保其整洁高效。 4. **数据库表结构优化** - **数据...

    深度分析mysql GROUP BY 与 ORDER BY

    本文就和大家一起深入研究下mysql中group by与order by.下面是我模拟我的内容表   我现在需要取出每个分类中最新的内容 select * from test group by category_id order by `date` 结果如下   明显。这不是我想...

    Mysql优化方法介绍.ppt

    在SQL语句层面,应避免全表扫描,合理使用JOIN,减少子查询,优化GROUP BY和ORDER BY操作。使用EXPLAIN分析查询执行计划,找出可能的性能瓶颈。另外,适当使用缓存如MySQL的Query Cache,可以提升查询速度。对于大...

    Mysql优化 PPT

    这可能包括遵循规范的SQL编写习惯,避免在WHERE子句中使用函数,合理使用LIMIT和ORDER BY,以及避免过度依赖临时表。 总的来说,这份"Mysql优化 PPT"应该是一份全面的指南,帮助读者理解MySQL性能优化的各个方面,...

    mysql order by limit 的一个坑.docx

    MySQL Order By Limit 的一个坑 MySQL 是一种广泛使用的关系型数据库管理系统,它提供了强大的查询功能,其中 ORDER BY 和 LIMIT 两个关键字是最常用的查询语句。然而,在某些情况下,使用 ORDER BY 和 LIMIT 两个...

    Mysql中order by、group by、having的区别深入分析

    在MySQL数据库中,ORDER BY、GROUP BY 和 HAVING 子句是SQL查询中用于数据处理的关键组成部分,它们各自承担不同的任务,以帮助我们从数据库中提取有用的信息。 ORDER BY 子句主要用于对查询结果集进行排序。当你...

    mysql 优化.docx

    本文将从EXPLAIN命令、SQL语句优化、索引的使用、排序和限制、union和union all的差异、ORDER BY RAND()的优化、in和exists的区分、分页方式的优化、分段查询等角度来讨论MySQL优化策略。 一、EXPLAIN命令的使用 ...

    MySQL GUI Tools MYSQL优化工具

    - **查询优化**: 优化SQL语句,避免全表扫描和子查询,使用JOIN代替子查询,合理使用LIMIT和ORDER BY。 - **存储引擎选择**: 根据数据访问模式选择合适的存储引擎,如InnoDB支持事务处理,MyISAM适合读取密集型...

    mysql优化方案

    本文讨论了 MYSQL 优化方案的多个方面,涵盖 BIOS 设置优化、IO 子系统优化、Schema 设计优化、索引设计优化和无法使用索引的场景等方面的知识点,旨在帮助读者更好地了解 MYSQL 优化的方法和策略。

    MYSQL优化资料

    3. GROUP BY与ORDER BY:合理使用GROUP BY和ORDER BY,如果可能,将它们与索引配合使用。ORDER BY在没有索引时会导致全表扫描,GROUP BY需谨慎处理,因为它可能涉及临时表和排序。 二、存储引擎优化 1. InnoDB与...

    MySQL order by性能优化方法实例

    本文从原理以及优化层面介绍 order by 。 一 MySQL中order by的原理  1 利用索引的有序性获取有序数据  当查询语句的 order BY 条件和查询的执行计划中所利用的 Index 的索引键(或前面几个索引键)完全一致,且...

    mysql性能优化教程.pdf (by caoz)

    SELECT * FROM user WHERE area = '$area' AND sex = '$sex' ORDER BY lastlogin DESC LIMIT 0, 30; ``` - **解决方案**:创建`area + sex + lastlogin`的复合索引,这样可以同时利用地区和性别筛选结果,并按...

Global site tag (gtag.js) - Google Analytics