PHP MySQL选择两个随机行但不使用rand()

时间:2014-10-14 21:22:03

标签: php mysql random

我需要选择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,字段为:iduseridnicknameid是主要和自动增量。有些行也被删除,因此它不是1 2 3 4 5但是1 2 4 5 6 ...所以生成随机数并选择它们的解决方案不会起作用

3 个答案:

答案 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);

当然,如果您从表中添加或删除任何行,则必须对行重新编号。或者至少你可以更有效地做到这一点:

  • 如果插入,则插入具有随机值的新行,并将现有行的等级更新为$ max + 1。
  • 如果删除,请记下已删除行的排名,并将排名为$ max的行更新为刚刚删除的排名。