MySQL ORDER BY 的实现分析

下面将通过实例分析两种排序实现方式及实现图解:
假设有 Table A 和 B 两个表结构分别如下:
sky@localhost : example 01:48:21> show create table AG
*************************** 1. row ***************************
Table: A
Create Table: CREATE TABLE `A` (
`c1` int(11) NOT NULL default ‘0′,
`c2` char(2) default NULL,
`c3` varchar(16) default NULL,
`c4` datetime default NULL,
PRIMARY KEY  (`c1`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

sky@localhost : example 01:48:32> show create table BG
*************************** 1. row ***************************
Table: B
Create Table: CREATE TABLE `B` (
`c1` int(11) NOT NULL default ‘0′,
`c2` char(2) default NULL,
`c3` varchar(16) default NULL,
PRIMARY KEY  (`c1`),
KEY `B_c2_ind` (`c2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

1、利用有序索引进行排序,实际上就是当我们 Query 的 ORDER BY 条件和 Query 的执行计划中所利用的 Index 的索引键(或前面几个索引键)完全一致,且索引访问方式为 rang、 ref 或者 index 的时候,MySQL 可以利用索引顺序而直接取得已经排好序的数据。这种方式的 ORDER BY 基本上可以说是最优的排序方式了,因为 MySQL 不需要进行实际的排序操作。

假设我们在Table A 和 B 上执行如下SQL:
sky@localhost : example 01:44:28> EXPLAIN SELECT A.* FROM A,B
-> WHERE A.c1 > 2 AND A.c2 < 5 AND A.c2 = B.c2 ORDER BY A.c1G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Using where; Using index

我们通过执行计划可以看出,MySQL实际上并没有进行实际的排序操作,实际上其整个执行过程如下图所示:

2、通过相应的排序算法,将取得的数据在内存中进行排序方式,MySQL 比需要将数据在内存中进行排序,所使用的内存区域也就是我们通过 sort_buffer_size 系统变量所设置的排序区。这个排序区是每个 Thread 独享的,所以说可能在同一时刻在 MySQL 中可能存在多个 sort buffer 内存区域。

第二种方式在 MySQL Query Optimizer 所给出的执行计划(通过 EXPLAIN 命令查看)中被称为 filesort。在这种方式中,主要是由于没有可以利用的有序索引取得有序的数据,MySQL只能通过将取得的数据在内存中进行排序然后再将数据返回给客户端。在 MySQL 中 filesort 的实现算法实际上是有两种的,一种是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在 sort buffer 中进行排序。另外一种是一次性取出满足条件行的所有字段,然后在 sort buffer 中进行排序。

在 MySQL4.1 版本之前只有第一种排序算法,第二种算法是从 MySQL4.1开始的改进算法,主要目的是为了减少第一次算法中需要两次访问表数据的 IO 操作,将两次变成了一次,但相应也会耗用更多的 sort buffer 空间。当然,MySQL4.1开始的以后所有版本同时也支持第一种算法,MySQL 主要通过比较我们所设定的系统参数 max_length_for_sort_data 的大小和 Query 语句所取出的字段类型大小总和来判定需要使用哪一种排序算法。如果 max_length_for_sort_data 更大,则使用第二种优化后的算法,反之使用第一种算法。所以如果希望 ORDER BY 操作的效率尽可能的高,一定要主义 max_length_for_sort_data 参数的设置。曾经就有同事的数据库出现大量的排序等待,造成系统负载很高,而且响应时间变得很长,最后查出正是因为 MySQL 使用了传统的第一种排序算法而导致,在加大了 max_length_for_sort_data 参数值之后,系统负载马上得到了大的缓解,响应也快了很多。

我们再看看 MySQL 需要使用 filesort 实现排序的实例。

假设我们改变一下我们的 Query,换成通过A.c2来排序,再看看情况:
sky@localhost : example 01:54:23> EXPLAIN SELECT A.* FROM A,B
-> WHERE A.c1 > 2 AND A.c2 < 5 AND A.c2 = B.c2 ORDER BY A.c2G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Using where; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Using where; Using index

MySQL 从 Table A 中取出了符合条件的数据,由于取得的数据并不满足 ORDER BY 条件,所以 MySQL 进行了 filesort 操作,其整个执行过程如下图所示:

在 MySQL 中,filesort 操作还有一个比较奇怪的限制,那就是其数据源必须是来源于一个 Table,所以,如果我们的排序数据如果是两个(或者更多个) Table 通过 Join所得出的,那么 MySQL 必须通过先创建一个临时表(Temporary Table),然后再将此临时表的数据进行排序,如下例所示:

sky@localhost : example 02:46:15> explain select A.* from A,B
-> where A.c1 > 2 and A.c2 < 5 and A.c2 = B.c2 order by B.c3G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Using where

这个执行计划的输出还是有点奇怪的,不知道为什么,MySQL Query Optimizer 将 “Using temporary” 过程显示在第一行对 Table A 的操作中,难道只是为让执行计划的输出少一行?

实际执行过程应该是如下图所示:

时间: 2012-07-28

MySQL Order By用法分享

先按照下面的表结构创建mysql_order_by_test数据表,我们用实例一点一点告诉你,MySQL order by的用法. ORDER BY uid ASC 按照uid正序查询数据,也就是按照uid从小到大排列 ORDER BY uid DESC 按照uid逆序查询数据,也就是按照uid从大到小排列 我们来看 SELECT * FROM mysql_order_by_test ORDER BY uid ASC 这条语句是按照uid正序查询数据,也就是按照uid从小到大排列 返回的结果就是

深入解析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 by中最大的或最小的某一字段使用 max或min函数.例:select sum(click_num) as totalnum,max(update_time) as update_time,

MySQL Order By Rand()效率分析

最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1. 但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描.但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机. 但是真正测试一下

MySQL Order By语法介绍

今天在使用ORDER BY的过程中出现了一点问题,发现之前对ORDER BY理解是错误的. 之前在w3s网站上看到ORDER BY的用法,以为是对选出来的数据按关键字升序或者降序排列,结果今天尝试select数据集数据的时候,发现使用ORDER BY 和ORDER BY DESC得出的查询结果完全不一样,按照自己之前的理解它们应该是结果相同,而内部顺序不一样而已. 问了一下同事,查了一下文档,才恍然大悟.如果我们在执行select语句的时候使用ORDER BY (DESC),那么它首先会对所有记

MySQL Order by 语句用法与优化详解

MySQL Order By keyword是用来给记录中的数据进行分类的.MySQL Order By Keyword根据关键词分类ORDER BY keyword是用来给记录中的数据进行分类的. 复制代码 代码如下: SELECT column_name(s) FROM table_name ORDER BY column_name 例子 SQL创建代码: 复制代码 代码如下: CREATE TABLE IF NOT EXISTS mysql_order_by_test (  uid int

mysql分组取每组前几条记录(排名) 附group by与order by的研究

--按某一字段分组取最大(小)值所在行的数据 复制代码 代码如下: /* 数据如下: name val memo a 2 a2(a的第二个值) a 1 a1--a的第一个值 a 3 a3:a的第三个值 b 1 b1--b的第一个值 b 3 b3:b的第三个值 b 2 b2b2b2b2 b 4 b4b4 b 5 b5b5b5b5b5 */ --创建表并插入数据: 复制代码 代码如下: create table tb(name varchar(10),val int,memo varchar(20)

MySQL Order 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 ORD

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

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

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

order by 从英文里理解就是行的排序方式,默认的为升序. order by 后面必须列出排序的字段名,可以是多个字段名.  group by 从英文里理解就是分组.必须有"聚合函数"来配合才能使用,使用时至少需要一个分组标志字段. 什么是"聚合函数"? 像sum().count().avg()等都是"聚合函数" 使用group by 的目的就是要将数据分类汇总. 一般如: select 单位名称,count(职工id),sum(职工工资)

MySQL查询优化:连接查询排序limit(join、order by、limit语句)介绍

不知道有没有人碰到过这样恶心的问题:两张表连接查询并limit,SQL效率很高,但是加上order by以后,语句的执行时间变的巨长,效率巨低. 情况是这么一个情况:现在有两张表,team表和people表,每个people属于一个team,people中有个字段team_id. 下面给出建表语句: 复制代码 代码如下: create table t_team ( id int primary key, tname varchar(100) ); create table t_people (

mysql &quot;group by&quot;与&quot;order by&quot;的研究--分类中最新的内容

这两天让一个数据查询难了.主要是对group by 理解的不够深入.才出现这样的情况 这种需求,我想很多人都遇到过.下面是我模拟我的内容表 复制代码 代码如下: CREATE TABLE `test` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `category_id` INT(10) NOT NULL, `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMES

mysql中提高Order by语句查询效率的两个思路分析

因为可能需要对数据库的记录进行重新排序.在这篇文章中,笔者就谈谈提高Order By语句查询效率的两个思路,以供大家参考. 在MySQL数据库中,Order by语句的使用频率是比较高的.但是众所周知,在使用这个语句时,往往会降低数据查询的性能.因为可能需要对数据库的记录进行重新排序.在这篇文章中,笔者就谈谈提高Order By语句查询效率的两个思路,以供大家参考. 498)this.width=498;" border=0> 一.建议使用一个索引来满足Order By子句. 在条件允许的

MYSQL随机抽取查询 MySQL Order By Rand()效率问题

要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1. 但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描.但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机. 但是真正测试一下才发现这样效率非常低.一个15万余条的库,查询5条数据,居然要8秒

浅谈mysql的子查询联合与in的效率

最近的产品测试发现一个问题,当并发数量小于10时,响应时间可以维持在100毫秒以内.但是当并发数到达30个时,响应时间就超过1秒.这太不能接受了,要求是通过1秒中并发100个. 经过检测发现,时间主要是耗在其中的一个存储过程中.把存储过程的语句一条一条的过一遍也没有发现明显的不合理.因为mysql本身不能提供毫秒级别的时间,google了一个mysql的能提供毫秒的时间函数,再做测试,做了一个定位.发现是其中一条语句,语句是这个样子: select .... from A, B where ..

MYSQL 随机 抽取实现方法及效率分析

复制代码 代码如下: 请教怎么从数据库随机读出15条记录? order by rand() limit 0,15 怎么从数据库随机读出所有记录? order by rand() 但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描.但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机. 但是真正测试一下才发现这样效率非常低.一个15万余条的库,查询5条

mysql随机抽取一定数量的记录实例讲解

以前碰见这种使用场景都是直接order by rand()来处理的,但是效率实在是不敢恭维,所以最近又碰见这种场景,在网上找寻下比较好的解决办法. 1.order by rand() 写法: SELECT id FROM `table` ORDER BY rand() 这种写法的缺点是rand函数在order by中被执行多次,影响效率. 2.max(id) * rand() 使用join 写法: SELECT * FROM `table` AS t1 JOIN ( SELECT ROUND(

MySQL 随机查询数据与随机更新数据实现代码

MySQL随机查询数据 以前在群里讨论过这个问题,比较的有意思.MySQLl的语法真好玩.他们原来都想用PHP的实现随机,但取出多条好像要进行两次以上查询.翻了手册,找到了下面这个语句,可以完成任务了. 复制代码 代码如下: SELECT * FROM table_name ORDER BY rand() LIMIT 5; MySQL的rand()函数在手册里是这么说的: RAND() RAND(N) 返回在范围0到1.0内的随机浮点值.如果一个整数参数N被指定,它被用作种子值. 关于MySQL

mysql随机查询若干条数据的方法

在mysql中查询5条不重复的数据,使用以下: 复制代码 代码如下: SELECT * FROM `table` ORDER BY RAND() LIMIT 5 就可以了.但是真正测试一下才发现这样效率非常低.一个15万余条的库,查询5条数据,居然要8秒以上搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据. 复制代码 代码如下: SELECT * FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX

MySQL随机查询记录的效率测试分析

以下就是文章的主要内容. 1.SELECT * FROM `table` ORDER BY RAND() LIMIT 5 就可以了. 但是真正测试一下才发现这样效率非常低.一个15万余条的库,查询5条数据,居然要8秒以上 查看官方手册,也说rand()放在ORDER BY 子句中会被执行多次,自然效率及很低. You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evalu

MySQL中select语句使用order按行排序

本文介绍MySQL数据库中执行select查询语句,并对查询的结果使用order by 子句进行排序. 再来回顾一下SQL语句中的select语句的语法: Select 语句的基本语法: Select <列的集合> from <表名> where <条件> order by <排序字段和方式> 如果要对查询结果按某个字段排序,则要使用order by 子句,如下: select * from <表名> order by <字段名称>