4

我试图从一个包含大约 700 万条记录的表中获取 4 个随机结果。此外,我还想从同一个表中获取 4 个按类别过滤的随机记录。

现在,正如您想象的那样,对这么大的表进行随机排序会导致查询花费几秒钟,这并不理想。

我为non-filtered结果集想到的另一种方法是让 PHP 选择 1 - 7,000,000 左右之间的一些随机数,然后IN(...)使用查询来只抓取这些行 - 是的,我知道这种方法有需要注意的是,如果具有该 id 的记录不再存在,您可能会得到少于 4 个。

但是,上述方法显然不适用于类别过滤,因为 PHP 不知道哪些记录号属于哪个类别,因此无法选择要从中选择的记录号。

有没有更好的方法可以做到这一点?我能想到的唯一方法是将每个类别的记录 ID 存储在另一个表中,然后从中选择随机结果,然后在辅助查询中仅从主表中选择那些记录 ID;但我确定有更好的方法!?

4

4 回答 4

2

您当然可以使用and (对于类别)RAND()在查询中使用该函数。但是,正如您所指出的,这需要对数据库进行扫描,这需要时间,尤其是在您的情况下,由于数据量很大。LIMITWHERE

正如您所指出的,您的另一种选择是将 id/category_id 存储在另一个表中可能会更快一些,但该表上必须有一个LIMITand WHERE,它也将包含与主表相同数量的记录。

一种不同的方法(如果适用)是每个类别都有一个表并在其中存储 ID。如果您的类别是固定的或不经常更改,那么您应该能够使用该方法。在这种情况下,您将有效地WHERE从子句中删除,并且在每个类别表上获得 aRAND()LIMIT更快,因为每个类别表都将包含主表中的记录子集。

其他一些替代方法是仅针对该操作使用键/值对数据库。MongoDb 或 Google AppEngine 可以提供帮助,而且速度非常快。

你也可以在你的 MySQL 中使用主/从的方法。从站实时复制内容,但是当您需要执行昂贵的查询时,您查询从站而不是主站,从而将负载传递到另一台机器。

最后,您可以使用更容易安装和维护的 Sphinx。然后,您可以将这些类别查询中的每一个视为文档搜索,并让 Sphinx 随机化结果。这样你就可以将这个昂贵的操作转移到不同的层,让 MySQL 继续执行其他操作。

只是一些需要考虑的问题。

于 2012-09-10T17:45:44.363 回答
1

解决你的随机数方法

  • 获取数据库中的最大 id。
  • 创建一个临时表来存储您的匹配项。
  • 循环n次执行以下操作
    • 生成一个介于 1 和 maxId 之间的随机数
    • 获取记录 ID 大于随机数的第一条记录并将其插入临时表
  • 您的临时表现在包含您的随机结果。

或者您可以使用联合动态生成 sql 以一步完成查询。

   SELECT * FROM myTable WHERE ID > RAND() AND Category = zzz LIMIT 1
   UNION
   SELECT * FROM myTable WHERE ID > RAND() AND Category = zzz LIMIT 1
   UNION
   SELECT * FROM myTable WHERE ID > RAND() AND Category = zzz LIMIT 1
   UNION
   SELECT * FROM myTable WHERE ID > RAND() AND Category = zzz LIMIT 1

注意:我的sql可能无效,因为我不是mySql人,但理论应该是合理的

于 2012-09-10T17:52:05.963 回答
1

首先你需要得到行数......像这样

select count(1) from tbl where category = ? 然后选择一个随机数

$offset = rand(1,$rowsNum); 并选择具有偏移量的行

select * FROM tbl LIMIT $offset, 1

通过这种方式,您可以避免丢失 ID。唯一的问题是您需要多次运行第二个查询。在这种情况下,工会可能会有所帮助。

于 2012-09-10T17:54:06.573 回答
-1

对于 MySQl,您可以使用

兰德()

SELECT column FROM table
ORDER BY RAND()
LIMIT 4
于 2012-09-10T17:45:04.377 回答