MySQL Order by Rand() 替代方案

在操作数据库时, 经常会有随机取出一个(或多个)条目的需求. 许多时候, 我会直接使用这样的语句:
Select `value` from `data` where (condition...) order by RAND() limit 1
但是, 这样的代码有严重的效率问题. 使用order参数时, SQL后端对数据进行了部分的快速排序, 调用比较函数的期望次数是log(n), 是比较慢的.
对 limit k,1 的情况, 相当于做了快速选择, 效率恰好是 O(log(n)), 而当获取条目数变多时, 效率也会随之成倍增长.

一个常用的算法是先

SELECT COUNT(*) FROM `data` WHERE (condition...)

然后在php中随机选出位置

$offset=rand(0,$data[0]['COUNT(*)']-1);
SELECT `value` FROM `data` WHERE (condition...) limit {$offset},1

这样的写法有两个问题. 其一是操作不是元操作, 至少有两次连接数据库的过程. 其二是当需要取多组数据的时候, 不但无法保证不重复, 而且执行了多条单独的SQL语句, 每条语句发起连接的延迟都会增大页面本身的延迟.

很可惜, 在Limit后面加子查询的尝试失败了, MySQL并不允许出现类似于
Select * from `data` where 1 limit (select (...)),1
的语句.
有什么更好的方法呢?


发表评论

电子邮件地址不会被公开。 必填项已用*标注

Powered by WordPress. Design: Supermodne.