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


当前回答

如果可能的话,使用存储语句来避免RND()上的索引和创建记录编号字段的效率低下。

PREPARE RandomRecord FROM "SELECT * FROM table LIMIT ?,1";
SET @n=FLOOR(RAND()*(SELECT COUNT(*) FROM table));
EXECUTE RandomRecord USING @n;

其他回答

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

SELECT TOP 1 * FROM MyTable ORDER BY newid()

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

我还没看出来答案有什么不同。我有一个额外的约束条件,给定一个初始种子,每次都要选择相同的行集。

对于MS SQL:

最小的例子:

select top 10 percent *
from table_name
order by rand(checksum(*))

规范化执行时间:1.00

NewId()例子:

select top 10 percent *
from table_name
order by newid()

规范化执行时间:1.02

NewId()比rand(checksum(*))慢不了多少,所以您可能不希望对大型记录集使用它。

初始种子选择:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % seed) /* any other math function here */

如果给定一个种子,你需要选择相同的集合,这似乎是可行的。

而不是使用RAND(),因为它是不鼓励的,你可以简单地得到max ID (= max):

SELECT MAX(ID) FROM TABLE;

在1..Max (= My_Generated_Random)

My_Generated_Random = rand_in_your_programming_lang_function(1..Max);

然后运行SQL:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1

注意,它将检查id等于或高于所选值的任何行。 也可以在表中寻找行,并获得一个等于或低于My_Generated_Random的ID,然后修改查询如下:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1
 SELECT * FROM table ORDER BY RAND() LIMIT 1

正如@BillKarwin对@cnu回答的评论所指出的那样…

当与LIMIT结合使用时,我发现随机排序的JOIN比直接对实际行进行排序执行得更好(至少在PostgreSQL 9.1中)。 SELECT * FROM tbl_post AS t 加入…… JOIN (SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand 从tbl_post WHERE create_time >= 1349928000 ) r ON r.id = t.d id WHERE create_time >= 1349928000 AND… ORDER BY r.r rand 限制100

只要确保“r”为与它连接的复杂查询中的每个可能的键值生成一个“rand”值,但仍然尽可能限制“r”的行数。

CAST as Integer对于PostgreSQL 9.2特别有用,它对整型和单精度浮点类型有特定的排序优化。