[MySQL 优化] --order by 原理

一、简介:

大部分查询中都要使用到order by。那么处理排序的方法有两种:一种是使用索引,另外一种则是查询时候使用Filesort处理。

1. 利用索引进行排:

利用有序索引进行排序,当 Query ORDER BY 条件和 Query 的执行计划中所利用的 Index 的索引键完全一致,且索引访问方式为 rang、 ref 或者 index 的时候,MySQL 可以利用索引顺序而直接取得已经排好序的数据。因为 MySQL 不需要进行实际的排序操作

2. 利用内存或者磁盘排序算法:

1. single pass
1. two pass

优缺点对比

优点 缺点
使用索引 执行insert,update,delete查询时,索引已经排序好,只需要依次读取即可,处理速度快 1.处理insert,update,delete时需要额外添加索引,所以很慢 2.索引需要更多的磁盘空间需要合理的规划好 3.索引个数越多,越需要更多innodb缓冲池
使用Filesort 1.因不必创建索引,故无使用索引时那么多的缺点 2.若要排序的记录不多,在内存中进行Filesort处理,速度也非常快 1.因为要在执行查询时进行排序处理,目标的数据越多,则响应的速度会越慢

不能使用索引进行排序的场景:

  1. 排序的基准太多,无法依据某个基准创建索引
  2. 要对group by 的结果或者DISTINCT的结果进行排序时
  3. 对临时表的结果(union union all[5.7进行优化没有临时表的出现])重新排序时

二、 举例:

表结构:

5.7@3306>[employees]>show create table employees\G
*************************** 1. row ***************************
       Table: employees
Create Table: CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

1.使用索引进行排序:

5.7@3306>[employees]>desc select emp_no,first_name, last_name from employees order by emp_no desc limit 0,10;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------+
|  1 | SIMPLE      | employees | NULL       | index | NULL          | PRIMARY | 4       | NULL |   10 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------+

2.使用single pass:

5.7@3306>[employees]>show status like '%sort%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Sort_merge_passes | 0     |
| Sort_range        | 0     |
| Sort_rows         | 0     |
| Sort_scan         | 0     |
+-------------------+-------+
4 rows in set (0.00 sec)

5.7@3306>[employees]>select emp_no,first_name, last_name from employees order by first_name limit 100;
分析:将select的列,order 列放入到排序缓冲,进行排序处理,排序完成后,直接将排序缓冲中的内容返回。

5.7@3306>[employees]>show status like '%sort%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Sort_merge_passes | 0     |
| Sort_range        | 0     |
| Sort_rows         | 100   |
| Sort_scan         | 1     |
+-------------------+-------+
4 rows in set (0.00 sec)

5.7@3306>[employees]>desc  select emp_no,first_name, last_name from employees order by first_name limit 100;
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra          |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
|  1 | SIMPLE      | employees | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 299423 |   100.00 | Using filesort |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

那么这样会造成什么问题:IO,网络等

3.Two pass

5.7@3306>[employees]>show variables like "%max_length%";
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| max_length_for_sort_data | 1024  |
+--------------------------+-------+
1 row in set (0.00 sec)
排序的值需要大于上面的值

5.7@3306>[employees]>show status like '%sort%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Sort_merge_passes | 0     |
| Sort_range        | 0     |
| Sort_rows         | 0     |
| Sort_scan         | 0     |
+-------------------+-------+
4 rows in set (0.00 sec) 

5.7@3306>[employees]> select count(1) from ( select * from employees order by first_name desc limit 100000000 ) a;
+----------+
| count(1) |
+----------+
|   300024 |
+----------+
1 row in set (0.87 sec)

5.7@3306>[employees]>show status like '%sort%';
+-------------------+--------+
| Variable_name     | Value  |
+-------------------+--------+
| Sort_merge_passes | 25     |
| Sort_range        | 0      |
| Sort_rows         | 300024 |
| Sort_scan         | 1      |
+-------------------+--------+
4 rows in set (0.00 sec)
解释:Sort_merge_passes  超出sort buffer的值,将数据写入到了tmp file中

三、 优化filesort:

优先选择第一种using index 的排序方式,在第一种方式无法满足的情况下,尽可能让 MySQL 选择使用第二种单路算法来进行排序。这样可以减少大量的随机IO操作,很大幅度地提高排序工作的效率。
1、去掉不必要的字段
2、加大max_length_for_sort_data 参数的设置
3、增大sort buffer的设置

时间: 2024-10-25 05:20:22

[MySQL 优化] --order by 原理的相关文章

【MySQL】order by 原理以及优化

一 简介   偏向于业务的(MySQL)DBA或者业务的开发者来说,order by 排序是一个常见的业务功能,将结果根据指定的字段排序,满足前端展示的需求.然而排序操作也是经常出现慢查询排行榜的座上宾.本文将从原理和实际案例优化,order by 使用限制等几个方面来逐步了解order by 排序.二 原理     在了解order by 排序的原理之前,强烈安利两篇关于排序算法的文章 <归并排序的实现>  <经典排序算法>.MySQL 支持两种排序算法,常规排序和优化,并且在M

MySQL教程:用索引优化ORDER BY

关于建立索引的几个准则: 1.合理的建立索引能够加速数据读取效率,不合理的建立索引反而会拖慢数据库的响应速度. 2.索引越多,更新数据的速度越慢. 3.尽量在采用MyIsam作为引擎的时候使用索引(因为MySQL以BTree存储索引),而不是InnoDB.但MyISAM不支持Transcation. 4.当你的程序和数据库结构/SQL语句已经优化到无法优化的程度,而程序瓶颈并不能顺利解决,那就是应该考虑使用诸如memcached这样的分布式缓存系统的时候了. 5.习惯和强迫自己用EXPLAIN来

Mysql中order by语句的优化详解

在某些情况中,MySQL可以使用一个索引来满足ORDER BY子句,而不需要额外的排序.where条件和order by使用相同的索引,并且order by的顺序和索引顺序相同,并且order by的字段都是升序或者都是降序. 一.建议使用一个索引来满足Order By子句. 在条件允许的情况下,笔者建议最好使用一个索引来满足Order By子句.如此的话,就可以避免额外的排序工作.这里笔者需要强调的一点是及时Order By子句不确切匹配索引,但是只要Where子句中所有未使用的索引部分和所有

mysql索引提高优化order by语句用法介绍

先我们要注意一下 1>mysql一次查询只能使用一个索引.如果要对多个字段使用索引,建立复合索引. 2>在ORDER BY操作中,MySQL只有在排序条件不是一个查询条件表达式的情况下才使用索引. 关于索引一些说法 MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通过索引优化来实现MySQL的ORDER BY语句优化: 1.ORDER BY的索引

mysql优化limit查询语句的5个方法_Mysql

mysql的分页比较简单,只需要limit offset,length就可以获取数据了,但是当offset和length比较大的时候,mysql明显性能下降 1.子查询优化法 先找出第一条数据,然后大于等于这条数据的id就是要获取的数据 缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性,具体方法请看下面的查询实例: 复制代码 代码如下: mysql> set profiling=1; Query OK, 0 rows affected (0.00

MYSQL实现ORDER BY LIMIT的方法以及优先队列(堆排序)

一.MYSQL中的LIMIT和ORACLE中的分页 在MYSQL官方文档中描述limit是在结果集中返回你需要的数据,它可以尽快的返回需要的行而不用管剩下的行, 在ORACLE中也有相关的语法比如 12C以前的rownun<n,也是达到同样的效果,同时limit也能做到分页查询如 limit n,m  则代表返回n开始的m行,ORACLE 12C以前也有分页方式但是相对比较麻烦 那么如果涉及到排序呢?我们需要返回按照字段排序后的某几行: MYSQL: select * from test ord

十大MySQL优化技巧

WEB开发者不光要解决程序的效率问题,对数据库的快速访问和相应也是一个大问题.希望本文能对大家掌握MySQL优化技巧有所帮助. 1. 优化你的MySQL查询缓存 在MySQL服务器上进行查询,可以启用高速查询缓存.让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一.当同一个查询被执行多次时,如果结果是从缓存中提取,那是相当快的. 但主要的问题是,它是那么容易被隐藏起来以至于我们大多数程序员会忽略它.在有些处理任务中,我们实际上是可以阻止查询缓存工作的. 1. // query cache d

【JAVA秒会技术之玩转SQL】MySQL优化技术(二)

MySQL优化技术(二) [前文连接]MySQL优化技术(一) (五)常用SQL优化 1.默认情况,在使用group by 分组查询时,会先分组,其后还会默认对组内其他条件进行默认的排序,可能会降低速度.这与在查询中指定order by col1, col2类似. 如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序. 例子:   2.尽量使用左连接(或右连接)来替代普通多表联查.因为使用JOIN,MySQL不需要在内存中创建临时表.    s

MySQL 第九篇:Mysql 与 ORACLE 开发差异、Mysql 优化

我把MySQL的内容整理成9篇博客,学完这9篇博客虽不能说能成为大神,但是应付一般中小企业的开发已经足够了,有疑问或建议的欢迎留言讨论. Mysql 与 ORACLE 开发差异 一. 常用的基本数据类型对比 二. 常用 SQL函数以及其它语法差异 Mysql 优化 一. 数据库设计 a) 适当的违反三大范式. b) 适当建立索引. c) 对表进行水平划分(按照一个周期对表数据进行拆分). d) 对表进行垂直划分(对字段内容较长的字段进行拆分到一个新表). e) 选择合适的字段类型.能占用字节小的