MySQL - 从大表中选择随机行

时间:2016-09-07 21:25:59

标签: php mysql random

如果这个话题已经完成,我很抱歉,但我正在努力从大型MySQL表中选择一个随机行。它是一个名为photos的表,其主键是PhotoID。目前它的ID范围从大约1500(由于在测试中创建的行然后删除)到~12000,有一些差距,我预计它会变得更大。

虽然它已经相对较小,但我一直在使用:

 SELECT PhotoID FROM photos

...进入PHP数组$All_IDs,然后用PHP:

 $RandomID = $All_IDs[mt_rand(0,count($All_IDs)-1)]

然后:

 SELECT /* other columns */ FROM photos WHERE PhotoID = $RandomID

这很好用,当我重复时,我会得到一系列随机照片。但是,我不认为它会非常有效地加载整个PhotoID列来选择一个随机ID,然后另一个查询来获取该记录,特别是如果我是将要选择几个。同样地,我不想将整个表(所有列)选择成一个数组,只是为了挑出一个。在其他一些StackOverflow答案的帮助下,我想出了以下内容:

SELECT MIN(PhotoID) INTO @MinID FROM photos;
SELECT MAX(PhotoID) INTO @MaxID FROM photos;
SELECT PhotoID,/* other columns */ FROM photos WHERE PhotoID >= (@MinID + RAND() * (@MaxID - @MinID)) ORDER BY PhotoID LIMIT 0,1

我认为这样可行但我发现多次重复这个查询只能让我在1500 - 1700范围内短暂传播ID,如上所述,ID&#39 ;目前流向12,000。我无法理解为什么会这样?

2 个答案:

答案 0 :(得分:1)

我怀疑您看到的范围很小,因为RAND()(在WHERE子句中)正在为表中的每个行进行评估。而且,行上的PhotoID更可能大于右侧表达式返回的较低值。因此查询返回一个更加加权到较低PhotoID值的集合。使用ORDER BY,您将获得最低价。

要获得更随机的分布,您需要在一个时间内评估RAND()。此外,当我可以在单个语句中完成工作并且没有用户定义的变量时,我不想执行多个查询(三个单独的SELECT语句)。

为了实现这个算法看起来你正试图实现,我接近这样的事情:

  SELECT t.photoid 
       , ...
    FROM photos t
    JOIN ( SELECT m.min_id + RAND() * (max_id - min_id) AS _rand
             FROM ( SELECT MIN(p.photoid) AS min_id
                         , MAX(p.photoid) AS max_id
                      FROM photos p
                   ) m
         ) r
      ON r._rand <= t.photoid
   ORDER BY t.photoid
   LIMIT 1

在MySQL中,内联视图(MySQL用语中的派生表)将首先在外部查询之前实现。由于m返回单行,r中的RAND()函数只会被评估一次。然后表达式中的单个值将用于外部查询。

答案 1 :(得分:0)

尝试此查询:

select * from photos order by rand() limit 1;