优化的方法来获取每个组的前n条记录

p1iqtdky  于 2021-06-23  发布在  Mysql
关注(0)|答案(1)|浏览(307)

我需要一个mysql表中每个子类别的前6条记录,这个表有将近100k条记录。我尝试了下面的mysql查询,但是我担心它在有大量记录的表中的性能。

SELECT 
    *
FROM
    (SELECT 
        sub_cat_id,
        title,      
        @rn:=IF(@prev = sub_cat_id, @rn + 1, 1) AS rn,
        @prev:=sub_cat_id AS previd,
        created_date
    FROM
        blog
    WHERE
        type = 'BLOG'
            AND FIND_IN_SET(sub_cat_id, '1,2,8')
            AND created_date <= NOW()
    ORDER BY sub_cat_id DESC , created_date DESC) AS records
WHERE
    rn <= 6

在上面的查询中,mysql将对所有子类id为1、2和8的记录进行编号。在outer select查询中,每个子类别的记录将减少到6条。
我有以下问题
对于每个子类别,这是获得6条记录的更好、最快的方法吗
此查询生成所需的结果。
这是我的博客表

+-------- +------------+-------+--------------+
| blog_id | sub_cat_id | title | created_date |
+-------- +------------+-------+--------------+
| 1       | 1          | ABC   | 2018-05-25   |
| 2       | 1          | ABC   | 2018-05-22   |
| 3       | 2          | ABC   | 2018-05-23   |
| 4       | 2          | ABC   | 2018-05-21   |
| 5       | 2          | ABC   | 2018-05-20   |
| 6       | 8          | ABC   | 2018-05-15   |
+-------- +------------+-------+--------------+
mnowg1ta

mnowg1ta1#

你的方法很好,但你的问题不是。特别是,mysql不能保证表达式的求值顺序 SELECT ,因此不应在一个表达式中指定变量,而在另一个表达式中使用它。
幸运的是,您可以将赋值组合成一个表达式:

SELECT b.*
FROM (SELECT b.sub_cat_id, b.title,  created_date     
             (@rn := IF(@sc = b.sub_cat_id, @rn + 1,
                        if(@sc := b.sub_cat_id, 1, 1)
                       )
             ) as rn
      FROM blog b CROSS JOIN
           (SELECT @sc := -1, @rn := 0) params
      WHERE b.type = 'BLOG' AND
            b.sub_cat_id IN (1, 2, 8) AND
            b.created_date <= NOW()  -- is this really needed?
      ORDER BY b.sub_cat_id DESC, b.created_date DESC) AS records
     ) b
WHERE rn <= 6;

对于这个查询,您需要索引。我认为这会奏效: type, sub_cat_id, created_date) . 不幸的是 group by 仍然需要对数据进行排序。在较新版本的mysql中,我认为您需要在子查询中进行排序,然后 rn 之后的任务。
我确实想知道这个公式是否能更有效:

select b.*
from blogs b
where b.type = 'BLOG' and
      b.sub_cat_id in (1, 2, 8) and
      b.created_at >= (select b2.created_at
                       from blogs b2
                       where b2.type = b.type and
                             b2.sub_cat_id = b.sub_cat_id
                       order by b2.created_at desc
                       limit 1 offset 5
                      );

对于这个,你需要一个索引 blog(type, sub_cat_id, created_at) .

相关问题