MySQL 中随机抽样:order by rand limit 的替代方案

摘要:
最近,由于需要粗略研究MYSQL的随机抽取实现方法。然而,在MYSQL3.23中,您仍然可以通过ORDER BYRAND()实现随机化。根据官方手册,rand()将在ORDER BY子句中执行多次,这自然是低效的。不能在ORDERBY子句中使用带有RAND()值的列,因为ORDERBY将多次计算该列。在搜索谷歌时,基本上可以查询max*rand()来随机获取数据。SELECT*FROM `table `ASt1JOINASt2WHEREt1.id˃=t2.idORDERBYt1.idASCLIMIT5;然而,这将导致五项连续记录。SELECT*FROM`table `WHEREid˃=ORDERBYidLIMIT1;在这种情况下,效率再次提高。查询时间仅为0.01秒。最后,改进语句并添加MIN判断。

  最近由于需要大概研究了一下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中使用函数效率还要高很多。

      参考文献:

MySQL Order By索引优化:http://www.phpq.net/mysql/mysql-order-by.html
MySQL Order By语法:http://www.phpq.net/mysql/mysql-order-by-syntax.html
MySQL Order By Rand()效率:http://www.phpq.net/mysql/mysql-order-by-rand.html
MySQL Order By用法:http://www.phpq.net/mysql/mysql-order-by-use.html

免责声明:文章转载自《MySQL 中随机抽样:order by rand limit 的替代方案》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Python 开发安卓Android及IOS应用库Kivy安装尝试第二章:NHibernate配置的总体流程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Socket Connect问题

一、非阻塞Connect对于Select时应注意的问题二、linux客户端socket非阻塞connect编程 一、非阻塞Connect对于Select时应注意的问题 对于面向连接的socket(SOCK_STREAM、SOCK_SEQPACKET),在读写数据之前必须建立连接。 建立连接的过程: 首先,服务器端socket必须在一个客户端知晓的地...

MySQL创建表

1.不控制主键的起点 -- 1.不控制主键的起点 create table emb_t_dictBusType ( emb_c_busTypeID int unsigned primary key not null auto_increment, emb_c_busTypeEnName varchar(255) not null,...

MySQL具体解释(8)----------MySQL线程池总结(二)

这篇文章是对上篇文章的一个补充,主要环绕下面两点展开。one-connection-per-thread的实现方式以及线程池中epoll的使用。 one-connection-per-thread 依据scheduler_functions的模板,我们也能够列出one-connection-per-thread方式的几个关键函数。 static sche...

【推荐】CentOS安装PHP5.6.4+扩展安装+安全配置+性能配置

注:以下所有操作均在CentOS 6.5 x86_64位系统下完成。 #准备工作# 前段时间PHP官方发布了一个重要的安全升级公告,修复了两个unserialize函数的严重漏洞,目前受影响的版本有: <5.4.36 <5.5.20 <5.6.4 这里我们直接下载5.6.4的版本进行安装配置,并且在这之前需要先把MySQL和Apach...

数据库系统Informix为例,介绍改善用户查询计划的方法。

数据库系统Informix为例,介绍改善用户查询计划的方法。 1.合理使用索引 索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率。现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构。索引的使用要恰到好处,其使用原则如下: ●在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则由优化器自动生成索引。 ●在频繁进行排...

mysql备份相关

1linux下mysql导出文件 备份mysql数据库的命令mysqldump -h主机名 -u用户名 -p密码 数据库名字 > 备份的数据库名字.sql 例如:mysqldump  -uroot -p1234 springboot   >/tmp/springboot.sql 仅仅备份数据库结构(不带表数据) mysqldump --no-...