随机抽取order By Rand()的效率问题和改进写法_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 1869 | 回复: 0   主题: 随机抽取order By Rand()的效率问题和改进写法        下一篇 
tngou
注册用户
等级:中校
经验:2433
发帖:192
精华:15
注册:2014-4-28
状态:离线
发送短消息息给tngou 加好友    发送短消息息给tngou 发消息
发表于: IP:您无权察看 2015-7-22 16:55:25 | [全部帖] [楼主帖] 楼主   主页

最近由于需要大概研究了一下MYSQL的随机抽取实现方法。

     举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是 SELECT * FROM tablename ORDER BY RAND() LIMIT 1

     但是,后来我查了一下MYSQL的官方手册,里面针对RAND()有如下提示:

You can’t use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. In MySQL Version 3.23, you can, however, do: SELECT * FROM table_name ORDER BY RAND()


      大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机。

     然后我试了一下可行性,ORDER BY RAND()在我自己的4.0版本上可以执行,但是在公司的3.x(具体忘了)上不能执行,看来好像和官方手册上有点不同。

     后来在网上找了一些资料了解到,

SELECT * FROM tablename ORDER BY RAND() LIMIT 1


      会扫描整个表,然后再随机返回一个记录。对于比较小的表,通常不大于30万行记录的表,这种写法很实用。但是如果一旦记录大于了30万行,这个处理过程就会变得非常缓慢!!!

     所以,结论是,我建议,能够不用ORDER BY RAND() 就不用!因为一来可以避免今后表数据量增大后引起的效率低下;二来可以避免某些版本的MYSQL不支持这种写法。

     最后给出一种比较实用的替代方法的主要思想:

     假设id是主键

     首先:SELECT MIN(id), MAX(id) FROM tablename

     然后:$id=rand($min,$max); //通过rand返回刚才取到的最大id和最小id之间的一个id号。

     最后:SELECT * FROM tablename WHERE id=’$id’ LIMIT 1

     如果是用auto increment产生的id号,也许会出现某个id列曾经删除过,造成了最大和最小id之间的不连续,在这里可以先判断一下随机生成的这个id号是否存在。

     我现在就使用order by rand(),当然数据表还很小很小。

     你这种方法也不错,但是如果我要随机的10条呢?最简单的就是随便取个连续的范围,比如

SELECT * FROM tablename WHERE id > ‘$id’ LIMIT 10


      但这种方法的随机是连续的.

     然后还有比如生成一个WHERE id = ‘{$id['1']}’ OR id = ‘{$id['2']}’ OR …..的从句,写起来会稍微多几句,$id的值随机生成数。

     但这种方法如果从句多了话,比如上百条?那样SQL语句会比较大,也会影响效率。

     还有,先按照第一种随机选择一个范围,比如

SELECT id FROM tablename WHERE id > ‘$id’ LIMIT 50


      然后再在在结果中随机选择10个

     还有,每次随机取一个,取10次。

     首先:SELECT MIN(id), MAX(id) FROM tablename

     然后:$id=rand($min,$max); //通过rand返回刚才取到的最大id和最小id之间的一个id号。

     最后:SELECT * FROM tablename WHERE id=’$id’ LIMIT 1

     如果记录的ID是唯一的,且记录有过删除,那很可能取到的这个ID就没有记录存在。

     所以如果用这个办法,一定要再select一下,看看这个记录是否存在了




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论