服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|

服务器之家 - 数据库 - Mysql - MySQL Order By Rand()效率分析

MySQL Order By Rand()效率分析

2019-12-06 15:52MySQL教程网 Mysql

本文详细解说了MySQL Order By Rand()效率优化的方案,并给出了优化的思路过程,是篇不可多得的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()来实现随机。 

但是真正测试一下才发现这样效率非常低。一个15万余条的库,查询5条数据,居然要8秒以上。查看官方手册,也说rand()放在ORDER BY 子句中会被执行多次,自然效率及很低。 
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. 
搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。 

复制代码代码如下:


SELECT * 
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2 
WHERE t1.id >= t2.id 
ORDER BY t1.id ASC LIMIT 5; 


但是这样会产生连续的5条记录。解决办法只能是每次查询一条,查询5次。即便如此也值得,因为15万条的表,查询只需要0.01秒不到。 

下面的语句采用的是JOIN,mysql的论坛上有人使用 

复制代码代码如下:


SELECT * 
FROM `table` 
WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) 
ORDER BY id LIMIT 1; 


我测试了一下,需要0.5秒,速度也不错,但是跟上面的语句还是有很大差距。总觉有什么地方不正常。 

于是我把语句改写了一下。 
SELECT * FROM `table` 
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM `table`))) 
ORDER BY id LIMIT 1; 

这下,效率又提高了,查询时间只有0.01秒 

最后,再把语句完善一下,加上MIN(id)的判断。我在最开始测试的时候,就是因为没有加上MIN(id)的判断,结果有一半的时间总是查询到表中的前面几行。 
完整查询语句是: 

复制代码代码如下:


SELECT * FROM `table` 
WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`))) 
ORDER BY id LIMIT 1; 

 

复制代码代码如下:


SELECT * 
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2 
WHERE t1.id >= t2.id 
ORDER BY t1.id LIMIT 1; 


最后在php中对这两个语句进行分别查询10次, 
前者花费时间 0.147433 秒 
后者花费时间 0.015130 秒 
看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。

延伸 · 阅读

精彩推荐
  • MysqlMySQL collation方法

    MySQL collation方法

    在以前用oracle的时候,很少关于它的collation方法,但是在mysql中,这点不加注意的话,却有可能会出现问题。 ...

    mysql教程网2542019-10-24
  • MysqlMysql自动备份与还原方法

    Mysql自动备份与还原方法

    Mysql自动备份与还原方法,需要的朋友可以参考下。 ...

    MYSQL教程网4212019-11-20
  • Mysql比较详细的MySQL字段类型说明

    比较详细的MySQL字段类型说明

    MySQL支持大量的列类型,它可以被分为3类:数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述,并且总结每个列类型的...

    mysql教程网2392019-10-24
  • Mysql完美转换MySQL的字符集 解决查看utf8源文件中的乱码问题

    完美转换MySQL的字符集 解决查看utf8源文件中的乱码问题

    本人转换过好多数据了,也用过了好多的办法,个人感觉最好用的就是使用MySQL命令导出导入中将字符集转换过去 ...

    MYSQL教程网4912019-11-27
  • Mysqlmysql5.7.23版本安装教程及配置方法

    mysql5.7.23版本安装教程及配置方法

    这篇文章主要介绍了mysql5.7.23版本安装教程及配置方法,需要的朋友可以参考下...

    桐一律3752019-06-16
  • Mysql查看MySQL的错误日志的方法

    查看MySQL的错误日志的方法

    我们经常在运行MySQL时会出一些错误,也经常被这些错误搞得晕头转向。当然解决这些问题的首要任务是找到日志信息。 ...

    mysql教程网3402019-11-10
  • Mysqlmysql的日期和时间函数大全

    mysql的日期和时间函数大全

    mysql的日期和时间函数 这里是一个使用日期函数的例子。下面的查询选择所有 date_col 值在最后 30 天内的记录。 ...

    mysql技术网3672019-10-21
  • MysqlMysql全文搜索match against的用法

    Mysql全文搜索match against的用法

    全文检索在 MySQL 中就是一个 FULLTEXT 类型索引。FULLTEXT 索引用于 MyISAM 表,可以在 CREATE TABLE 时或之后使用 ALTER TABLE 或 CREATE INDEX 在 CHAR、 VARCHAR 或 TEXT 列上...

    MYSQL教程网2642019-11-26