我需要选择2个随机行,但已知rand()太慢了。所以我尝试了网站上的代码,它是:
SELECT *
FROM bilder AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM bilder)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 2
但是这样我多次得到2行并且解析也不正确,所以这完全没用。是否有一个比rand()更好的工作解决方案?表名为bilder
,字段为:id
,userid
,nickname
。 id
是主要和自动增量。有些行也被删除,因此它不是1 2 3 4 5但是1 2 4 5 6 ...所以生成随机数并选择它们的解决方案不会起作用
答案 0 :(得分:2)
此问题有多种解决方案,但以下内容通常具有足够好的性能:
SELECT b.*
FROM bilder b CROSS JOIN
(SELECT COUNT(*) as cnt FROM bilder) v
WHERE rand() <= 100 / cnt
ORDER BY rand()
LIMIT 2;
子查询选择大约100行。对如此少量的行进行排序通常非常快。然后选择其中两个。
答案 1 :(得分:0)
令人惊愕的最可能原因是未能将RAND() * (SELECT MAX(id) FROM bilder)
包裹在对CEIL()
的调用中,导致浮动而不是整数:
SELECT *
FROM bilder AS r1 JOIN
(SELECT ceil(RAND() *
(SELECT MAX(id)
FROM bilder)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 2
答案 2 :(得分:0)
选择一个随机行的方法要快得多。以下两种方法都只选择一个随机行。你问了两个随机的行。但是这些方法比进行表扫描要快几个数量级,因此即使需要多次尝试才能获得第二个不同的随机行,所以使用这些方法也是值得的。
最快的方法是在两个查询中执行此操作(我将以伪代码显示):
$max = SELECT MAX(id) FROM bilder
$rand1 = rand(1..$max)-1
SELECT * FROM bilder WHERE id > $rand1 LIMIT 1
$id1 = id of the first row chosen
$rand2 = rand(1..$max)-1
SELECT * FROM bilder WHERE id > $rand2 AND id <> $id1 LIMIT 1
$id2 = id of the second row chosen
if $id2 = $id1, then choose a new $rand2 and query again
这样做的问题是,如果由于删除了行而导致间隙很大,那么选择跟踪间隙的行的可能性就会更大。
如果您不经常更新表,另一种快速方法是为连续排序添加一列,然后按随机顺序为该列分配顺序值:
ALTER TABLE bilder ADD COLUMN rank INT UNSIGNED, ADD KEY (rank);
SET @r := 0;
UPDATE bilder SET rank = (@r:=@r+1) ORDER BY RAND();
这次排名一次。它会很慢。然后,一旦对行进行排名,您就可以快速选择随机值:
$max = SELECT MAX(rank) FROM bilder;
$rand1 = rand(1..$max)
$rand2 = rand(1..$max) until $rand2 != $rand1
SELECT * FROM bilder WHERE rank IN ($rand1, $rand2);
当然,如果您从表中添加或删除任何行,则必须对行重新编号。或者至少你可以更有效地做到这一点: