如何在纯SQL中请求随机行(或尽可能接近真正的随机)?


当前回答

在MSSQL(在11.0.5569上测试)中使用

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10)

明显快于

SELECT TOP 100 * FROM employee ORDER BY NEWID()

其他回答

我不知道这有多有效,但我以前用过:

SELECT TOP 1 * FROM MyTable ORDER BY newid()

因为guid是非常随机的,所以顺序意味着您得到的是随机行。

我不得不同意CD-MaN:使用“ORDER BY RAND()”将很好地用于小表或当你只做几次SELECT时。

我还使用“num_value >= RAND() *…”技术,如果我真的想获得随机结果,我在表中有一个特殊的“随机”列,我大约每天更新一次。单个UPDATE运行将花费一些时间(特别是因为必须在该列上建立索引),但它比每次运行select时为每一行创建随机数快得多。

ORDER BY NEWID()

耗时7.4毫秒

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table)

只需要0.0065毫秒!

我肯定会选择后一种方法。

您也可以尝试使用new id()函数。

只需编写一个查询并使用order by new id()函数。它是随机的。

这里的大多数解决方案都旨在避免排序,但它们仍然需要对表进行顺序扫描。

还有一种方法可以通过切换到索引扫描来避免顺序扫描。如果你知道你随机行的下标值,你几乎可以立即得到结果。问题是——如何猜测一个索引值。

以下方案适用于PostgreSQL 8.4版本:

explain analyze select * from cms_refs where rec_id in 
  (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
   from generate_series(1,10))
  limit 1;

我上面的解决方案你猜10个不同的随机指标值从范围0 ..[id的最后一个值]。

数字10是任意的-你可以使用100或1000,因为它(令人惊讶的是)对响应时间没有太大的影响。

还有一个问题-如果你有稀疏的id,你可能会错过。解决方案是有一个备份计划:)在这种情况下,一个纯旧order by random()查询。当合并id看起来像这样:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
     from generate_series(1,10))
    union all (select * from cms_refs order by random() limit 1)
    limit 1;

不是union ALL条款。在这种情况下,如果第一部分返回任何数据,那么第二部分将永远不会执行!