mysql rand()替代[必须符合某些标准]

时间:2012-09-16 16:15:44

标签: mysql random

我当前的查询看起来像

SELECT *
FROM uploads
WHERE approved = 1
    AND (up-down) >= 3
ORDER BY RAND()
LIMIT 10

这是从DB中随机选择10个条目,其中至少有3个不喜欢。

问题是因为我在DB中有超过40k的条目,这个查询需要1秒钟。

我在谷歌上看了很多但到目前为止没有找到任何东西。

在我的情况下你有什么选择吗?

2 个答案:

答案 0 :(得分:1)

如果您要将所有匹配的记录加载到内存中,并且如果它们中没有太多,那么最简单的答案就是将order by放入SQL中,然后对它们进行排序随机在您的应用软件中。例如,如果你正在使用PHP,你只需将它们全部加载到一个数组中,然后调用array_rand()

如果这不是合适的答案,那么您仍然需要在数据库中对它们进行排序,那么在order by rand()太慢的情况下(即大多数情况下您有大量数据) ,我所知道的最佳解决方案如下:

向表中添加一个新列,并使用每个记录的主键的MD5哈希预填充它。并添加一个索引以按新字段排序。

这将为您提供表格的均匀分布的随机排序顺序。只需order by此字段代替rand()

答案 1 :(得分:0)

最佳方法取决于许多因素。以下是一些想法。

假设没有索引,当前版本的查询正在进行全表扫描,提取行,分配随机数,对行进行排序,然后选择前10个。

全表扫描第一次可能很慢,但在此之后应该非常快,假设表适合内存。我假设您的性能问题不是指查询的第一个实例,而是指该表已经在页面缓存中的那个。

如果“已批准”具有高度选择性 - 例如,1%的行已获批准 - 那么您可以通过在已批准的情况下构建索引来加快查询速度。

下一个选择是为“up-down”添加一列,并在两个密钥和已批准的UpMinusDown上构建索引。假设这是选择性的,它可以降低速度。

接下来的问题是,您是否可以将rand()替换为其他一些标准 - 例如,最新的10个标准。如果是这样,您可以包含一个主键说上载ID并将其用于排序。它会更快。

最后,如果您的记录非常广泛,那么它可能会占用时间。在这种情况下,我想知道以下版本的查询是否会表现更好:

SELECT *
FROM uploads u left outer join
     (select UploadID
      from uploads
      WHERE approved = 1
            AND (up-down) >= 3
     ORDER BY RAND()
     LIMIT 10
    ) random
    on u.UploadID = random.UploadID

(这假设您在表上有一个名为UploadID的主键。)

此版本应仅对UpLoadID进行排序,然后使用索引将其连接回原始数据。