在MySQL中为n个组选择随机子集


Select random subset for n groups in MySQL

我有一个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.0000名玩家,C组包含2.000名玩家和D组包含2.0000名玩家。

现在我的问题是:
我应该在PHP还是MySQL中这样做?(我想MySQL可能会更快)
在MySQL中,有比为每一行生成随机数并按顺序排列行,然后使用OFFSET和LIMIT来选择行更好(更有效)的方法吗?

我认为最有效、最简单的方法是运行以下查询:

SELECT * FROM players
ORDER BY rand()

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

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

您可以在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;