MySQL - 从大表中选择随机行

Posted

技术标签:

【中文标题】MySQL - 从大表中选择随机行【英文标题】:MySQL - selecting random row from large table 【发布时间】:2016-09-07 21:25:58 【问题描述】:

如果这个话题已经完成到死,我深表歉意,但我正在努力从一个大型 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,然后再进行另一个查询以获取该记录的效率不会很高,特别是如果我要选择几个。同样,我宁愿不选择整个表(所有列)到一个数组中只是为了挑选一个。在其他一些 *** 答案的帮助下,我得出了以下结论:

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

我认为这会起作用,但我发现重复此查询几次只会给我一小段 ID,在 1500 - 1700 范围内,而如上所述,ID 当前接近 12,000。我不明白这是为什么?

【问题讨论】:

【参考方案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() 函数将只计算一次。然后表达式中的单个值将用于外部查询。

【讨论】:

那太理想了,谢谢...我避免使用ORDER BY RAND(),因为我知道每行都会调用RAND(),但我认为如果它是@987654328 的一部分,它只会被调用一次@ 子句。我也从没想过这样使用JOIN 注意:这种方法不一定是从集合中返回随机行的最佳方法。我试图解释原始查询所观察到的行为的原因,以及一个实现原始查询预期设计的示例。 (在这种情况下使用 JOIN 是可行的,因为内联视图 r 将返回单行。)如果出于某种原因您需要使用多个语句,就像原来的一样,请将 RAND() 操作移到单独的语句中,然后将 single 静态值传递给实际查询。这就是这个答案中的查询正在做什么。)【参考方案2】:

试试这个查询:

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

【讨论】:

请注意,MySQL 将为表中的 每一 行评估 RAND() 函数。然后结果集将需要“使用文件排序”操作来识别具有最低 RAND() 值的行。这种方法往往不适用于大型集合。

以上是关于MySQL - 从大表中选择随机行的主要内容,如果未能解决你的问题,请参考以下文章

从mysql中的大表中快速选择随机行

在PostgreSQL中选择N个匹配条件的随机行

从大表的子集中对随机行进行最快查询 - postgresql

MySQL nodejs 在从大表中选择数据时崩溃

从大表中选择非空字段

(PHP) MySQL 随机行大表,具有 order by 和一定范围