获得每组最佳记录的优化方式

时间:2018-05-30 12:14:59

标签: mysql stored-procedures greatest-n-per-group mysql-variables

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

<div class="core">
     <div class="boxName"><span>Title</span></div>
     <div class="basicInfo">
        How to set height of this div to the bottom of core div?
     </div>
</div>

在上面的查询中,MySQL将对具有sub_cat_id 1,2和8的所有记录进行编号。在外部选择查询中,记录将减少每个子类别的6条记录。

我有以下问题

  • 这是为每个子类别获取6条记录的更好,最快的方式
  • 此查询是否会生成所需的结果。

这是我的博客

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

1 个答案:

答案 0 :(得分:2)

您的方法很好,但您的查询却没有。特别是,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)上的索引。