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

时间:2016-04-02 02:11:02

标签: 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;

表格结构:

table Articles
- id (int)
 - category (varchar)
 - title (varchar)
 - image (varchar)
 - link (varchar)
 - Counter (int)
 - dateStamp (datetime)

2 个答案:

答案 0 :(得分:0)

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

您将创建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

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

<强>更新

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

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

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

如果您的情况过于挑剔(例如只有1%的文章有category='entertainment'),那么简单的ORDER BY RAND()会更快,因为否则您需要创建太多的随机ID。但是,符合条件ORDER BY RAND()的最多10K行将足够快。

答案 1 :(得分:0)

您的“娱乐”条目应该都有唯一的ID,应该是整数。

如果是这种情况,您可以使用PHP的rand()函数在1和您拥有的条目数之间生成6个随机int。这是我写的一个可能有用的函数。

function selectSixRandomEntries() {
    $queryWhere = "";
    $i = 0;

    while($i < 6) {
        $randomNumber = rand(1, 200);
        if (strpos($queryWhere, $randomNumber) == -1)
            continue;

        $queryWhere .= "r1.id = " . rand(1, 200);
        if ($i != 5)
            $queryWhere .= " OR ";

        $i++;
    }

    return $queryWhere
}

要使用它,你可以尝试

$query = "SELECT
    r1.*
FROM
    Articles AS r1
    INNER JOIN (SELECT(RAND() * (SELECT MAX(id) FROM Articles)) AS id) AS r2
WHERE
    " . selectSixRandomEntries() . " 
    AND r1.category = 'entertainment'
LIMIT 6";