加快分组
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
考虑以下查询:
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