Php 这是从表中选择随机行的快速方法吗

Php 这是从表中选择随机行的快速方法吗,php,mysql,Php,Mysql,我读过一篇关于如何从包含大量数据的SQL表中随机选择一行(具有特定条件)的文章。它们得到id的最大值和最小值,并在它们之间生成一个随机数,然后得到id大于该值的第一行。但是,我的ID分布不均匀,所以我没有得到真正随机的行。例如,如果我的ID是1100、101,那么我几乎没有机会获得后面的两行 但我想到了另一个解决办法。我不获取max id,而是计算查询中的所有行,获取一个随机数I并选择第I个。代码如下所示 $count_res = $mysqli->query("SELECT COUNT(

我读过一篇关于如何从包含大量数据的SQL表中随机选择一行(具有特定条件)的文章。它们得到id的最大值和最小值,并在它们之间生成一个随机数,然后得到id大于该值的第一行。但是,我的ID分布不均匀,所以我没有得到真正随机的行。例如,如果我的ID是1100、101,那么我几乎没有机会获得后面的两行

但我想到了另一个解决办法。我不获取max id,而是计算查询中的所有行,获取一个随机数I并选择第I个。代码如下所示

$count_res = $mysqli->query("SELECT COUNT(*) FROM quest WHERE category IN ({$mem['my_cate']})");
$count = $count_res->fetch_array();
$rand_id = rand(0, $count[0] - 1);

$result = $mysqli->query("SELECT * FROM quest WHERE category IN ({$mem['my_cate']}) LIMIT 1 OFFSET $rand_id");

然而,我怀疑它的有效性。有谁能告诉我这方面的想法,或者为我的案件提出一个解决方案。谢谢。

使用以下内容可能会更快:

$result = $mysqli->query("SELECT * FROM quest WHERE category IN ({$mem['my_cate']}) ORDER BY Rand() LIMIT 1");

因为它只使用一个查询,您可以跳过顶部的一位。您可以通过在循环中尝试两种方法来对其进行基准测试数千次或您决定的任何次数,并比较循环前后的microtime()。

好的,我已经做了一些基准测试。我创建了一个只有一列自动递增id的表。然后我添加了1700000条记录。由于只有一个专栏,我认为它将比实际更快,但以下是我的基准:

方法1:选择行数,然后使用PHP选择一个随机数,然后根据偏移量进行选择。(我将偏移量设置在表格的末尾,因为它比表格的开头慢)

选择计数:12毫秒

选择偏移量:513ms

总数:525ms

方法2:在整个表中选择1,并使用RAND()

总数:2190ms

获胜者=方法1

可能的方法3:这只是我想出来的,不一定在所有情况下都有效。因此,我们的想法是获取表中最后一个自动递增id,生成一个介于1和最后一个自动递增编号之间的随机数,然后选择大于或等于该id编号的第一行。您必须大于或等于,因为可能缺少id号

选择最后一个id:10.1ms

选择随机行:6.3ms


总计:16.4ms

当我需要一个类似的查询时,我研究了一段时间,这与我最终使用的方法相同。如果您使用的是MYISAM,count()会很快,而且您没有使用ORDER BY which会有所帮助。你做过一些基准测试吗?使用一个大的
偏移量
会导致延迟,因为MySQL实际上必须遍历结果集才能到达请求的位置(不同于选择第一个大于给定值的ID,它可以检查索引以找到合适的行)。@markdwhite:no,我只在我的小表上进行了测试。@Amber:那么我们有解决方案了吗?@dvtrung94除了向数据中添加索引且均匀分布的id列之外,没有其他解决方案。按兰德排序()可能是解决这一问题最低效的方法。要按随机数排序,数据库必须遍历整个数据集,并为每个记录分配一个随机数,以便它可以对其进行排序。非常感谢。不幸的是,我无法使id的分布均匀(因为我从表中选择了带有某些条件的行)。也许我会考虑基于返回表的大小使用这两种方法。有趣的是,我没有考虑到方法3,差距越大,所选择的间隙的行的概率越大。