2

我有这张桌子:

person_id int(10) pk
fid bigint(20) unique
points int(6) index
birthday date index
4 FK columns int(6)
ENGINE = MyISAM

重要信息:该表包含超过 800 万行并且正在快速增长(目前每天 150 万)

我想要什么:当我在点上订购表格时,在一定范围内选择 4 个随机行

我现在怎么做:在 PHP 中,我随机化了一个特定的范围,假设这给了我 20% 的低范围和 30% 的高范围。接下来我计算(*)表中的行数。在我确定最低行数后:表数/100 * 低范围。高范围也一样。在我使用 rand(lowest_row,highest_row) 计算随机行之后,这给了我一个范围内的行号。最后我通过执行以下操作选择随机行:

SELECT * FROM `persons` WHERE points > 0 ORDER BY points desc LIMIT $random_offset, 1;

点 > 0 在查询中,因为我只想要至少 1 点的随机数。

上面的查询大约需要 1.5 秒才能运行,但由于我需要 4 行,所以需要 6 秒以上,这对我来说太慢了。我认为按点排序最耗时,所以我正在考虑制作表格的视图,但我真的没有视图的经验,所以你怎么看?视图是一个好的选择还是有更好的解决方案?

添加:

我忘了说重要的是所有行都有相同的被选中的机会。

谢谢,我感谢所有的帮助!:)

凯文

4

2 回答 2

1

您的查询非常慢,并且会以指数级速度变慢,因为LIMIT在这里使用会强制它进行全表排序,然后进行全表扫描,以获得结果。相反,您也应该在 PHP 端执行此操作(这种“滥用”LIMIT实际上是它是非标准 SQL 的原因,例如 MSSQL 和 Oracle 不支持它)。

首先确保points. 这将产生select max(points), min(points) from persons一个立即返回的查询。接下来,您可以从这 2 个结果中确定点范围,并用于rand()确定请求范围内的 4 个点。然后对每个结果重复:

SELECT * FROM persons WHERE points < $myValue ORDER BY points DESC LIMIT 1

由于它只需要检索一行,并且可以通过索引确定哪一行,因此执行时间也将在毫秒内。

于 2013-05-20T23:33:11.607 回答
1

视图不会对您在此处的表现有任何帮助。我的建议是简单地运行:

SELECT * FROM `persons` WHERE points BETWEEN ? AND ?

确保你有一个关于点的索引。此外,如果适用,您应该*只替换您关心的字段。这是当然?代表您搜索的上限和下限。

mysqli_num_rows()然后,您可以使用(或基于您选择的数据库库的类似方法)确定结果集中返回的行数。

您现在拥有符合条件的总行数。然后,您可以轻松地计算结果范围内的 4 个随机数,并使用mysqli_data_seek()或类似方法直接进入随机偏移处的记录并从中获取所需的值。

把它们放在一起:

$result = mysqli_query($db_conn, $sql); // here $sql is your SQL query
$num_records = 4; // your number of records to return
$num_rows = mysqli_num_rows($result);
$rows = array();

while ($i = 0; $i < $num_records; $i++) {
   $random_offset = rand(0, $num_rows - 1);
   mysqli_data_seek($result, $random_offset);
   $rows[] = mysqli_fetch_object($result);
}

mysqli_free_result($result);
于 2013-05-20T23:50:09.047 回答