比当前查询更好的方法来组合随机分类条目?

use*_*120 5 php mysql database-schema

我正在尝试准确显示6个随机的"娱乐"条目,但是根据我当前的查询,它会获得1到6之间的随机数,并显示该条目数.如何更新此查询以使其显示我的文章表中的6个随机娱乐条目?另外,我不想做ORDER BY RAND()因为我的桌子会加班加点.这是我当前的查询:

SELECT
    r1.*
FROM
    Articles AS r1
    INNER JOIN (SELECT(RAND() * (SELECT MAX(id) FROM Articles)) AS id) AS r2
WHERE
    r1.id >= r2.id
    AND r1.category = 'entertainment'
LIMIT 6;
Run Code Online (Sandbox Code Playgroud)

表结构:

table Articles
- id (int)
 - category (varchar)
 - title (varchar)
 - image (varchar)
 - link (varchar)
 - Counter (int)
 - dateStamp (datetime)
Run Code Online (Sandbox Code Playgroud)

Pau*_*gel 0

select floor(rand() * m.maxId + 1) as randomId
from Articles a
join (SELECT MAX(id) maxId FROM Articles) m
limit 100
Run Code Online (Sandbox Code Playgroud)

您将创建 100 个随机 ID。我取 100 是因为 id 列中有间隙,因此无法获得足够的现有 id 的可能性会(非常)小。然后您可以使用该结果仅选择具有这些 id 的 6 行:

select distinct a.*
from (
    select id, floor(rand() * m.maxId + 1) as randomId
    from Articles a
    join (SELECT MAX(id) maxId FROM Articles) m
    limit 100
) r
join Articles a on a.id = r.randomId
order by r.id -- only need it for small tables. will slow down the query on big tables
limit 6
Run Code Online (Sandbox Code Playgroud)

子选择中的最佳值LIMIT取决于 id 中的间隙百分比。100应该足够而且快。

更新

如果需要过滤,category可以在andWHERE a.category = 'entertainment'之前添加子句。但在这种情况下,您将需要调整生成的随机 ID 的数量。ORDER BYLIMIT

例如:如果您插入了 1M 篇文章,但其中 10% 被删除,那么平均有 90 个随机生成的 id 确实存在。如果现在 10% 的文章具有category = 'entertainment',则平均有 9 个随机行将匹配该条件。平均数- 可能是 3,也可能是 16。因此,您需要生成更多随机 ID 以确保您至少获得 6 篇文章。通过LIMIT 1000子选择,您将平均获得 90 篇随机娱乐文章。这样你就不太可能得到少于 6 的结果。所以你需要知道你的表的统计数据才能选择一个好的LIMIT.

该子句的另一个问题WHERE是 MySQL 可能会反转连接顺序以使用索引进行过滤。对于少量生成的随机 id 来说,这可能会更快,但如果子LIMIT选​​择中的 id 很大,则可能会更慢。STRIGHT_JOIN您可以通过使用而不是JOIN-来强制连接顺序,但在我的测试中LIMIT 10000它并没有产生可测量的差异。

如果您的条件过于选择性(例如,只有 1% 的文章有category='entertainment'),则简单的ORDER BY RAND()可能会更快,因为否则您将需要创建太多随机 id。但最多 10K 行匹配您的条件ORDER BY RAND()就足够快了。