Mysql学习浅谈MySQL排序原理与案例分析
《Mysql学习浅谈MySQL排序原理与案例分析》要点: MYSQL学习前言 MYSQL学习排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct语句都会隐含使用排序.本文首先会简单介绍SQL如何利用索引避免排序代价,然后会介绍MySQL实现排序的内部原理,并介绍与排序相关的参数,最后会给出几个“奇怪”排序例子,来谈谈排序一致性问题,并说明产生现象的本质原因. MYSQL学习1.排序优化与索引使用 MYSQL学习为了优化SQL语句的排序性能,最好的情况是避免排序,合理利用索引是一个不错的方法.因为索引本身也是有序的,如果在需要排序的字段上面建立了合适的索引,那么就可以跳过排序的过程,提高SQL的查询速度.下面我通过一些典型的SQL来说明哪些SQL可以利用索引减少排序,哪些SQL不能.假设t1表存在索引key1(key_part1,key_part2),key2(key2) MYSQL学习a.可以利用索引避免排序的SQL MYSQL学习
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 ORDER BY key_part1 ASC;
SELECT * FROM t1 WHERE key_part1 = constant1 AND key_part2 > constant2 ORDER BY key_part2;
MYSQL学习b.不能利用索引避免排序的SQL MYSQL学习
//排序字段在多个索引中,无法使用索引排序
SELECT * FROM t1 ORDER BY key_part1,key_part2,key2;
//排序键顺序与索引中列顺序不一致,无法使用索引排序
SELECT * FROM t1 ORDER BY key_part2,key_part1;
//升降序不一致,无法使用索引排序
SELECT * FROM t1 ORDER BY key_part1 DESC,key_part2 ASC;
//key_part1是范围查询,key_part2无法使用索引排序
SELECT * FROM t1 WHERE key_part1> constant ORDER BY key_part2;
MYSQL学习2.排序实现的算法 MYSQL学习对于不能利用索引避免排序的SQL,数据库不得不自己实现排序功能以满足用户需求,此时SQL的执行计划中会出现“Using filesort”,这里需要注意的是filesort并不意味着就是文件排序,其实也有可能是内存排序,这个主要由sort_buffer_size参数与结果集大小确定.MySQL内部实现排序主要有3种方式,常规排序,优化排序和优先队列排序,主要涉及3种排序算法:快速排序、归并排序和堆排序.假设表结构和SQL语句如下: MYSQL学习
CREATE TABLE t1(id int,col1 varchar(64),col2 varchar(64),col3 varchar(64),PRIMARY KEY(id),key(col1,col2));
SELECT col1,col2,col3 FROM t1 WHERE col1>100 ORDER BY col2;
MYSQL学习a.常规排序 MYSQL学习3.排序不一致问题 MYSQL学习案例1 MYSQL学习Mysql从5.5迁移到5.6以后,发现分页出现了重复值. MYSQL学习
create table t1(id int primary key,c1 int,c2 varchar(128));
insert into t1 values(1,1,'a');
insert into t1 values(2,2,'b');
insert into t1 values(3,'c');
insert into t1 values(4,'d');
insert into t1 values(5,3,'e');
insert into t1 values(6,4,'f');
insert into t1 values(7,5,'g');
MYSQL学习假设每页3条记录,第一页limit 0,3和第二页limit 3,3查询结果如下: MYSQL学习 MYSQL学习我们可以看到 id为4的这条记录居然同时出现在两次查询中,这明显是不符合预期的,而且在5.5版本中没有这个问题.产生这个现象的原因就是5.6针对limit M,N的语句采用了优先队列,而优先队列采用堆实现,比如上述的例子order by c1 asc limit 0,3 需要采用大小为3的大顶堆;limit 3,3需要采用大小为6的大顶堆.由于c1为2的记录有3条,而堆排序是非稳定的(对于相同的key值,无法保证排序后与排序前的位置一致),所以导致分页重复的现象.为了避免这个问题,我们可以在排序中加上唯一值,比如主键id,这样由于id是唯一的,确保参与排序的key值不相同.将SQL写成如下: MYSQL学习
select * from t1 order by c1,id asc limit 0,3;
select * from t1 order by c1,id asc limit 3,3;
MYSQL学习案例2 MYSQL学习两个类似的查询语句,除了返回列不同,其它都相同,但排序的结果不一致. MYSQL学习
create table t2(id int primary key,status int,c1 varchar(255),c2 varchar(255),c3 varchar(255),key(c1));
insert into t2 values(7,'a',repeat('a',255),255));
insert into t2 values(6,'b',255));
insert into t2 values(5,'c',255));
insert into t2 values(4,255));
insert into t2 values(3,255));
insert into t2 values(2,255));
insert into t2 values(1,255));
MYSQL学习分别执行SQL语句: MYSQL学习
select id,status,c1,c2 from t2 force index(c1) where c1>='b' order by status;
select id,status from t2 force index(c1) where c1>='b' order by status;
MYSQL学习执行结果如下: MYSQL学习 MYSQL学习看看两者的执行计划是否相同 MYSQL学习 MYSQL学习为了说明问题,我在语句中加了force index的hint,确保能走上c1列索引.语句通过c1列索引捞取id,然后去表中捞取返回的列.根据c1列值的大小,记录在c1索引中的相对位置如下: MYSQL学习(c1,id)===(b,6),(b,3),(5,c),(c,2),对应的status值分别为2 3 2 4.从表中捞取数据并按status排序,则相对位置变为(6,b),(3,(2,这就是第二条语句查询返回的结果,那么为什么第一条查询语句(6,c)是调换顺序的呢?这里要看我之前提到的a.常规排序和b.优化排序中标红的部分,就可以明白原因了.由于第一条查询返回的列的字节数超过了max_length_for_sort_data,导致排序采用的是常规排序,而在这种情况下MYSQL将rowid排序,将随机IO转为顺序IO,所以返回的是5在前,6在后;而第二条查询采用的是优化排序,没有第二次捞取数据的过程,保持了排序后记录的相对位置.对于第一条语句,若想采用优化排序,我们将max_length_for_sort_data设置调大即可,比如2048. MYSQL学习 MYSQL学习下面是本人关于mysql 自定义排序(field,INSTR,locate)的一点心得,希望对大家有所帮助 MYSQL学习原表: MYSQL学习
id user pass
aaa aaa
bbb bbb
ccc ccc
ddd ddd
eee eee
fff fff
MYSQL学习下面是我执行后的结果: MYSQL学习
SELECT * FROM `user` order by field(2,id) asc
MYSQL学习
id user pass
aaa aaa
ccc ccc
ddd ddd
eee eee
fff fff
bbb bbb
MYSQL学习根据结果分析:order by field(2,6) 结果显示顺序为:1 3 4 5 6 2 MYSQL学习
SELECT * FROM `user` order by field(2,id) desc
MYSQL学习
id user pass
bbb bbb
aaa aaa
ccc ccc
ddd ddd
eee eee
fff fff
MYSQL学习根据结果分析:order by field(2,6) 结果显示顺序为:2 1 3 4 5 6 MYSQL学习
SELECT * FROM `user` ORDER BY INSTR( '2,4',id ) ASC
MYSQL学习
id user pass
aaa aaa
fff fff
bbb bbb
ccc ccc
eee eee
ddd ddd
MYSQL学习根据结果分析:order by INSTR(2,6) 结果显示顺序为:1 6 2 3 5 4 MYSQL学习
SELECT * FROM `user` ORDER BY INSTR( '2,id ) DESC
MYSQL学习
id user pass
ddd ddd
eee eee
ccc ccc
bbb bbb
aaa aaa
fff fff
MYSQL学习根据结果分析:order by INSTR(2,6) 结果显示顺序为:4 5 3 2 1 6 MYSQL学习
SELECT * FROM `user` ORDER BY locate( id,'2,4' ) ASC
MYSQL学习? id? user? pass? MYSQL学习
aaa aaa
fff fff
bbb bbb
ccc ccc
eee eee
ddd ddd
MYSQL学习根据结果分析:order by locate(2,6) 结果显示顺序为:1 6 2 3 5 4 MYSQL学习
SELECT * FROM `user` ORDER BY locate( id,4' ) DESC
MYSQL学习
id user pass
ddd ddd
eee eee
ccc ccc
bbb bbb
aaa aaa
fff fff
MYSQL学习根据结果分析:order by locate(2,6) 结果显示顺序为:4 5 3 2 1 6 MYSQL学习
id user pass
bbb bbb
ccc ccc
eee eee
ddd ddd
aaa aaa
fff fff (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |