MySQL中order by的实现 和 by rand() 和优化

“MySQL 里面的order by rand()”是怎么实现的。我们今天来简单说说MySQL里的order by。
    几种order by的情况             香格里拉娱乐城
    乍一看这个问题好像有点复杂,我们从最简单的case开始看起。
    用这个表来说明:(10w行数据)

1、  最简单的order ―― order by索引字段

从explain的结果来看(Extra列),这个语句并不作排序。因为字段a已经是有顺序的。就是按照索引a的顺序依次读pk的值(在这里是隐藏的系统列),一个个从聚簇索引的data中读入。

2、  复杂一点 ―― order by 非索引字段

    这里Extra列显示一个Using filesort。这里的filesort并不是指字面上的“文件排序”,说的就是与上面一种情况相比,在Server层作了排序。至于是否使用文件,取决于排序过程中的内存是否足够,不够则需要临时文件。

并不到此为止,我们细细想一下,server层要怎么作排序呢
    一个简单的想法是把表数据都读到内存,然后排序。读到内存当然可以想怎么整就怎么整。但是这个做法很耗费内存。需要占用与表一样大小的内存。

另外一个做法,只读入字段b和其对应的主键id。可以想象为这两个字段构成的结构体,按照b的值作排序。排序完成后,按字段b的顺序依次取主键id,取得结果返回。

实际上第二种作法就是这个例子中的实际执行过程。存放用于排序的字段值的结构我们称为sort_keys.
至于order by b,c这样的语句,效果与order by b相同,可以简单理解为上面结构体多了一个字段。

3、  字段函数排序
     有了上面的流程,这里就简单了,还是按顺序读入所有的字段b,只是sort_keys中存的是b的长度而已。

4、Order by rand()
    按照自然想法, order by rand() 也可以仿照上面描述的做法,对于每一行,将生成的rand()的值放入sort_kyes里即可。但实际上上效果如下:

    Extra字段里面有一个Using temporary, 也就是说用到了临时表。那么Using temporary的时候操作流程是怎样的呢?
    a)   创建一个heap引擎的临时表,字段名为 ”” a b c d, 第一个字段为匿名;
    b)   将表tb中的数据按行读入到临时表中,同时给第一字段填入一个随机实数(0,1);
    c)   按照第一个字段排序,返回
    d)   查询完成删除临时表
    分析一下这个过程,由于把数据从InnoDB表里面读入临时表,则InnoDB表实际上也已经读入内存,在这个过程中,若不考虑内存不够时的写文件策略, 则内存中有两份表的全拷贝;另外多了从内存中将数据一一拷贝到临时表的过程。

这个查询在我的测试环境中耗时2.41s(多次次执行,不计第一次加载数据的时间)

order by rand()的改进
    我们前面说过,实际上对于这种简单的order by rand() 的情况,也可以等同于按照非索引字段来处理。在sort_array 中存入随机值即可。
     按照这个思路的patch在这里,效果上

执行时间减少为1.89s,性能提升21%, 这个例子单行1k,单行越大提升效果越好。

MySQL中order by的实现 和 by rand() 和优化

时间: 2025-01-10 06:45:53

MySQL中order by的实现 和 by rand() 和优化的相关文章

MySQL中order by中关于NULL值的排序问题

MySQL中order by 排序遇到NULL值的问题 MySQL数据库,在order by排序的时候,如果存在NULL值,那么NULL是最小的,ASC正序排序的话,NULL值是在最前面的. 如果我们想让NULL排在后面,让非NULL的行排在前面该怎么做呢? MySQL数据库在设计的时候,如果字段允许NULL值,那么对该字段进行排序的时候需要注意那些值为NULL的行. 我们知道NULL的意思表示什么都不是,或者理解成"未知"也可以,它与任何值比较的结果都是false, 默认情况下,My

mysql 中order by 与group by的顺序

mysql 中order by 与group by的顺序 是: select from where group by order 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 upd

MySQL中order by排序时,数据存在null咋办

order by排序是最常用的功能,但是排序有时会遇到数据为空null的情况,这样排序就会乱了,这里以MySQL为例,记录我遇到的问题和解决思路. 问题: 网页要实现table的行鼠标拖拽排序,我用AngularJs集成了一个TableDnD开源插件,可以实现,然后在数据库表中增加一个排序字段indexId,但是原来的大量数据是没有排序过的,所以该字段为null. 这样order by时,为null的数据就会排在最前边. 写个测试表模拟一下,如下效果: 解决办法: 最优办法:利用MySQL中的一

MySQL中order by语句对null字段的排序

默认情况下,MySQL将null算作最小值. 如果想要手动指定null的顺序,可以使用: 将null强制放在最前: if(isnull(字段名),0,1) asc   //asc可以省略 将null强制放在最后 if(isnull(字段名),0,1) dsc if(isnull(字段名),1,0)  asc   //asc可以省略 对于这种使用方式的理解: 以if(isnull(字段名),0,1)为例,它的意思是将该字段根据是否为null值分成两部分,值为null行相当于得到了一个隐含的排序属性

mysql中group by和order by混用 结果不是理想结果

在使用mysql排序的时候会想到按照降序分组来获得一组数据,而使用order by往往得到的不是理想中的结果,那么怎么才能使用group by 和order by得到理想中的数据结果呢? 例如 有一个 帖子的回复表,posts( id , tid , subject , message ,  dateline ) , id为 自动增长字段, tid为该回复的主题帖子的id(外键关联),  subject 为回复标题, message 为回复内容, dateline 为回复时间,用UNIX 时间戳

MySQL中union和order by一起使用的方法

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

MySQL中如何查看“慢查询”,如何分析执行SQL的效率?

一.MySQL数据库有几个配置选项可以帮助我们及时捕获低效SQL语句 1,slow_query_log这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句. 2,long_query_time当SQL语句执行时间超过此数值时,就会被记录到日志中,建议设置为1或者更短. 3,slow_query_log_file记录日志的文件名. 4,log_queries_not_using_indexes这个参数设置为ON,可以捕获到所有未使用索引的SQL语句,尽管这个SQL语句有可能执行得挺快. 二

批量 kill mysql 中运行时间长的sql

转自:思齐-批量 kill mysql 中运行时间长的sql 以下内容来自mysql手册: 13.5.5.3. KILL语法KILL [CONNECTION | QUERY] thread_id每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. KILL允许自选的CONNECTION或QUERY修改符: · KILL CONNECTION与不含修改符的KILL一样:它会终止与给

mysql中的索引原理与表设计

索引是有效使用数据库的基础,但你的数据量很小的时候,或许通过扫描整表来存取数据的性能还能接受,但当数据量极大时,当访问量极大时,就一定需要通过索引的辅助才能有效地存取数据.一般索引建立的好坏是性能好坏的成功关键. 1.InnoDb数据与索引存储细节 使用InnoDb作为数据引擎的Mysql和有聚集索引的SqlServer的数据存储结构有点类似,虽然在物理层面,他们都存储在Page上,但在逻辑上面,我们可以把数据分为三块:数据区域,索引区域,主键区域,他们通过主键的值作为关联,配合工作.默认配置下