从大表中获取随机结果

时间:2012-09-10 17:34:21

标签: php mysql large-data-volumes

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

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

我为non-filtered结果集考虑的另一种方法是让PHP选择1到7,000,000之间的一些随机数,然后使用查询进行IN(...)只抓取那些行 - 是的,我知道这个方法有一个警告,如果一个具有该id的记录不再存在,你可能会少于4。

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

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

4 个答案:

答案 0 :(得分:2)

您当然可以使用RAND()LIMIT(对于类别)在查询中使用WHERE函数。然而,正如您所指出的那样,需要对数据库进行扫描,这需要花费时间,特别是在您的情况下由于数据量的原因。

你的另一个选择,就像你指出的那样,将id / category_id存储在另一个表中可能会更快一些,但同样必须在该表上有一个LIMITWHERE包含与主表相同数量的记录。

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

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

您也可以在MySQL中使用Master / Slave。从站实时复制内容,但是当您需要执行昂贵的查询时,您会查询从站而不是主站,从而将负载传递给其他计算机。

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

只需考虑一些问题。

答案 1 :(得分:1)

使用随机数方法

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

或者您可以使用union动态生成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人,但理论应该是合理的

答案 2 :(得分:1)

首先,您需要获得行数......就像这样

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

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

select * FROM tbl LIMIT $offset, 1

通过这种方式你可以避免错过ID。唯一的问题是您需要多次运行第二个查询。在这种情况下,联盟可能会提供帮助。

答案 3 :(得分:-1)

对于MySQl,您可以使用

  

RAND()

SELECT column FROM table
ORDER BY RAND()
LIMIT 4