【问题标题】:Select random subset for n groups in MySQL在 MySQL 中为 n 个组选择随机子集
【发布时间】:2013-09-02 23:43:52
【问题描述】:

我有一个 MySQL 表 players,我正在尝试将所有玩家随机分成 n 个组 (n>=2),其中每个组都有确定但可变的大小。

示例时间:

将表 players 中的 10.000 行分成 3 个组,其中 A 组包含 5.000 名玩家,B 组包含 3.000 名玩家,C 组包含 2.000 名玩家。

另一个例子可能是:

players 表中的 10.000 行分成 4 个组,其中 A 组包含 3.000 名玩家,B 组包含 3.000 名玩家,C 组包含 2.000 名玩家,D 组包含 2.000 名玩家。

现在我的问题:
我应该在 PHP 或 MySQL 中执行此操作吗? (我在想 MySQL 可能会更快)
在 MySQL 中是否有更好(更有效)的方法来执行此操作,而不是为每一行生成随机数并按此排序行,然后使用 OFFSET 和 LIMIT 来选择行?

【问题讨论】:

    标签: php mysql sql random


    【解决方案1】:

    我认为最有效和最简单的方法是运行此查询:

    SELECT * FROM players
    ORDER BY rand()
    

    然后在几个 PHP FOR 循环中迭代结果(每组一个)。

    这样,您将只运行一个查询并迭代一次结果(这是您实际上必须做的事情)。

    【讨论】:

    • 确实如此。但是您可以进行类似行为的查询可能需要更多时间。检查此link。考虑到您不想只获得随机行,而是获得以前未选择的随机行。这意味着您还必须跟踪这一点,我相信这将比 rand() 花费更长的时间。但是您应该尝试这两种方法,看看哪一种表现更好(并报告回来,因为我也很感兴趣 :)
    【解决方案2】:

    您可以在 MySQL 中执行此操作。策略如下。随机化行并枚举它们。然后计算每个组的枚举间隔。

    select t.*,
           (case when (seqnum - 1) / totalcnt < 0.3 then 'GroupA'
                 when (seqnum - 1) / totalcnt < 0.6 then 'GroupB'
                 when (seqnum - 1) / totalcnt < 0.8 then 'GroupC'
                 else 'GroupD'
            end) as WhichGroup
    from (select t.*, @rn := @rn + 1 as seqnum, totalcnt
          from t cross join
               (select @rn := 0, count(*) as totalcnt from t) const
          order by rand()
         ) t;
    

    order by rand() 确实会减慢速度。然而,获取随机样本并不是一个天生的快速过程。

    一种更快的方法 - 创建与您正在寻找的大小略有不同的组 - 是执行以下操作:

    select t.*,
           (case when rand() < 0.3 then 'GroupA'
                 when rand() < 0.6 then 'GroupB'
                 when rand() < 0.8 then 'GroupC'
                 else 'GroupD'
            end) as WhichGroup
    from t;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      相关资源
      最近更新 更多