加快分组

Speed up group by

考虑以下查询:

select * 
  from `cg_reviews` 
 inner join `cg_park` on `cg_park`.`cg_id` = `cg_reviews`.`cgr_cg_id` 
 where `status` = 'approved' 
   and `cgr_approval_time` > 0 
 group by `cg_park`.`cg_id` 
 order by `cgr_approval_time` desc limit 3

它基本上要求一个公园的所有批准评论,按批准时间排序,每个公园只有 1 个评论。意思是,我不希望每个公园有超过 1 个评论,因此 3 个结果中的每一个都必须来自不同的公园 (cg_id)。

此查询有效,但即使使用我能想到的每个索引,在 18687 行上仍然很慢。当我删除 group by 子句时,它快如闪电。我还能如何使用独特的公园进行此查询?

最好在加入之前而不是之后在更大的 table 中进行分组。

SELECT *
FROM (
    SELECT *
    FROM cg_reviews
    WHERE cgr_approval_time > 0
    AND status = 'approved'
    GROUP BY cgr_cg_id
) AS cgr
INNER JOIN cg_park AS cgp ON cgp.cg_id = cgr.cgr_cg_id
ORDER BY cgr_approval_time DESC
LIMIT 3

确保 cgr_cg_id 上有索引(如果声明为 FOREIGN KEY,索引将自动创建)。

请注意,此分组不会产生可靠的结果。由于 cg_reviews 的行不是由您分组所依据的列唯一确定的,因此您将从每个组中的任意行中获取列。您可能应该看到 SQL select only rows with max value on a column 如何在每个组中 select 明确定义的行(例如,具有最近批准时间的行)。

根据您对 APPROVED 评论的评论,我必须假设 "status" 列在评论 table 上。最好总是有 table.column 或 alias.column 这样其他人就不必猜测哪一列属于哪里。

就是说,我会有一个多列索引来帮助排序和分组。具体

table        index
cg_reviews   ( status, cgr_cg_id, cgr_approval_time )

您的公园 table cg_id = 评论 cgr_cg_id,因此由于它们具有相同的值,您的分组依据可以是 "cgr_cg_id" 并利用索引.

在不查看数据的情况下,每个 "cgr_cg_id" 可能有 100 条评论,而您只关心最新的...因此,您只需要前 3 条。这部分查询没有与 PARK table 相关,可以通过

完成
select
      r.cgr_cg_id,
      max( r.cgr_approval_time ) latestReview,
   from
      cg_reviews r
   where
          r.status = 'approved'
      and r.cgr_approval_time > 0
   group by
      r.cgr_cg_id
   order by
      max( r.cgr_approval_time ) DESC
   limit 3

所以现在您从所有评论中获得了 3 条记录。分组依据是公园 ID 列,并且由于按每组最近的最长时间排序,因此您不会获得具有多个评论的同一个公园。最后,您需要将详细信息呈现给最终用户。这应该很快,因为我们现在可以回到公园并查看 table 这三个记录,并且应该通过使用相同的索引几乎是即时的。只需将上述查询作为您的第一个查询,给它一个别名

select
      r2.*,
      p.*
   from
      ( select
            r.cgr_cg_id,
            max( r.cgr_approval_time ) latestReview,
         from
            cg_reviews r
         where
                r.status = 'approved'
            and r.cgr_approval_time > 0
         group by
            r.cgr_cg_id
         order by
            max( r.cgr_approval_time ) DESC
         limit 3 ) PQ

         JOIN cg_reviews r2
            on r2.status = 'approved'
           AND PQ.cgr_cg_id = r2.cgr_cg_id 
           AND PQ.latestReview = r2.cgr_approval_time

         JOIN cg_park p
            on PQ.cgr_cg_id = p.cg_id