Mysql 获得每组前n名记录的优化方法

Mysql 获得每组前n名记录的优化方法,mysql,stored-procedures,greatest-n-per-group,mysql-variables,Mysql,Stored Procedures,Greatest N Per Group,Mysql Variables,我需要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_da

我需要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不保证
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;

为此,您需要在
blog(type,sub\u cat\u id,created\u at)上创建一个索引

您的方法是正确的,但您的查询不是。特别是,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;

为此,您需要在
blog(type,sub\u cat\u id,created\u at)上创建一个索引

如果第二个选项更快,我会有点惊讶@还有,让我们知道是不是。第二个查询更好。但不会生成任何结果。如果每个子类别只包含2条记录,则上述查询中的偏移量5将失败。@Anoop。我不明白你的意见。要么查询不起作用,要么更快。哪一个?它怎么不起作用?只有当没有足够的行时?@GordonLinoff第一个查询对我来说很好,但第二个查询不起作用。我试图更正第二个查询,以便检查哪一个更快。我喜欢你的第二个查询,但它不起作用。如果第二个选项更快,我会有点惊讶@还有,让我们知道是不是。第二个查询更好。但不会生成任何结果。如果每个子类别只包含2条记录,则上述查询中的偏移量5将失败。@Anoop。我不明白你的意见。要么查询不起作用,要么更快。哪一个?它怎么不起作用?只有当没有足够的行时?@GordonLinoff第一个查询对我来说很好,但第二个查询不起作用。我试图更正第二个查询,以便检查哪一个更快。我喜欢你的第二个查询,但它不起作用。
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
                      );