我当前的查询看起来像这样
SELECT *
FROM uploads
WHERE approved = 1
AND (up-down) >= 3
ORDER BY RAND()
LIMIT 10
这是从 DB 中随机选择 10 个条目,其中至少 3 个喜欢多于不喜欢。
问题是因为我在 DB 中有超过 40k 条目,而这个查询需要 1 秒。
我在谷歌上读了很多,但到目前为止没有找到任何东西。
在我的情况下,您有什么替代方案可以推荐吗?
如果您将所有匹配的记录加载到内存中,并且它们的数量不多,那么最简单的答案就是将其order by
放入您的 SQL 中,并在您的应用程序软件中对它们进行随机排序。例如,如果您使用的是 PHP,您可以简单地将它们全部加载到一个数组中,然后调用array_rand()
.
如果这不是一个合适的答案,那么您仍然需要在数据库中对它们进行排序,那么在order by rand()
太慢的情况下(即大多数情况下您有大量数据),我所知道的最佳解决方案是如下:
向您的表中添加一个新列,并使用每条记录的主键的 MD5 哈希预填充它。并添加一个索引以按新字段排序。
这将为您提供表的均匀分布的随机排序顺序。只需order by
此字段而不是rand()
.
最佳方法取决于许多因素。这里有一些想法。
假设没有索引,当前版本的查询正在执行全表扫描、提取行、分配随机数、对行进行排序,然后选择其中的前 10 个。
全表扫描第一次可能很慢,但之后应该会很快,假设表适合内存。让我假设您的性能问题不是指查询的第一个实例,而是指表已经在页面缓存中的一个实例。
如果“已批准”具有高度选择性——例如,1% 的行被批准——那么您可以通过在已批准上建立索引来加快查询速度。
下一个替代方法是为“up-down”添加一列,并在两个键上建立索引,approved 和 UpMinusDown。假设这是选择性的,它可以降低速度。
下一个问题是您是否可以用rand()
其他一些标准替换 —— 例如,最近的 10 个。如果是这样,您可以包含一个主键,例如 UploadID 并将其用于排序。它会走得更快。
最后,如果您的记录非常广泛,那么它可能会占用时间。在这种情况下,我想知道以下版本的查询是否会执行得更好:
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 进行排序,然后使用索引将其连接回原始数据。