为啥一个 group by 的聚合这么慢?
Posted
技术标签:
【中文标题】为啥一个 group by 的聚合这么慢?【英文标题】:Why is an aggregation with a group by so slow?为什么一个 group by 的聚合这么慢? 【发布时间】:2021-10-17 09:55:39 【问题描述】:我在 Redshift 实例中有一个表 [order]
,行数为 780 000。
在表上运行以下 group by 子句需要 60 多秒。
在 MSSQL 中,完全相同的查询需要 1 秒。
任何关于 Redshift 为什么需要这么长时间以及如何改进查询的建议都将不胜感激。
select
salesorderid
,max(orderid) as max_order_id
,min(latestdelivery) as min_latestdelivery
,max(latestdelivery) as max_latestdelivery
,min(sourceid) as min_sourceid
,max(sourceid) as max_sourceid
,min(salesitem) as min_salesitem
,max(salesitem) as max_salesitem
,min(qty) as min_qty
,max(qty) as max_qty
,min(weight) as min_weight
,max(weight) as max_weight
,min(refb) as min_refb
,max(refb) as max_refb
,min(blocked) as min_blocked
,max(blocked) as max_blocked
,min(updatemode) as min_updatemode
from public.order o
where o.datecreated >= getdate() - interval '24 month'
group by salesorderid;
解释:
XN HashAggregate (cost=35513.57..52310.29 rows=419918 width=99)
-> XN Seq Scan on "order" o (cost=0.00..9738.60 rows=606470 width=99)
Filter: (datecreated >= '2019-10-17 11:52:14'::timestamp without time zone)
【问题讨论】:
您是如何插入数据的?用什么命令? 桌子上的 SORTKEY 是什么? @JohnRotenstein +1 - 还有:DISTKEY 是什么? 你的salesorderid
s 是独一无二的吗?
很遗憾我没有插入数据,所以我无法提供插入命令。 SORTKEY 已启用(salesorderid,datecreated)。 DISTKEY 已启用(创建日期)。 salesorderis 不是唯一的。
【参考方案1】:
虽然这里有几处不理想的地方,但可能需要 1 分钟的原因不在 SQL 中。我会逐项列出我稍后看到的问题。
您的源表少于 1M 行 - 按照 Redshift 标准来说非常小。排序顺序或元数据陈旧不太可能导致大问题。该查询是一个简单的聚合,解释计划显示 Redshift 预计此“应该”花费不到一秒的时间。所有这些都让我将注意力集中在外部混杂因素上。
我将假设您是从工作台测量查询时间,而不是通过系统表数据。如果不是这种情况,请告诉我们。如果是这样,您正在查看数据库的完整往返行程,而不仅仅是执行时间。完成查询需要执行多个步骤。它需要通过 WLM 队列进行编译、调度、执行和返回结果。这些步骤中的任何一个都可能需要很长时间,每个步骤都有很多原因。
因此,第一步是找出查询在每个步骤中所用的时间。我喜欢从中间开始(排队和执行,因为这通常是事情变慢的地方,但并非总是如此)。 STL_WLM_QUERY 系统表将显示您的查询通过队列花费了多长时间以及执行时间。一种可能性是您的查询在队列中等待而挂起,您应该这样做。它还将显示总执行时间,以便您查看运行所需的时间(这是 EXPLAIN 计划的全部重点)。可能这里有问题,但我会继续阅读。
如果事情快速通过队列并在合理的时间内执行,那么我们需要查看编译并返回。 SVL_COMPILE 将显示查询编译所用的时间,但鉴于此查询的简单性,这不太可能是您的问题所在。
可能的原因在于返回步骤。 EXPLAIN 期望您收到 419K 行有意义的宽度 - 这可能代表相当数量的数据。如果您与 Redshift 和您自己之间的网络带宽有限,那么这些数据量可能会占用您运行时间的很大一部分来传输。 STL_RETURN 从 Redshift 的角度保存这一步的数据。您还可以通过将结果放入临时表中重新运行查询来测试这一点,看看这是否大大提高了运行时间。这只是我的猜测。
正确的做法是收集有关时间花费的数据并根据这些信息采取行动。如果此时需要更多指导,请报告此问题。
现在对查询本身进行一些观察。我建议您不要使用时间戳作为表的分布键。您不太可能通过时间戳加入或分组,这对执行查询没有帮助。由于您按 salesorderid 分组,这可能是分发键的不错选择。此外,您应该使用常见的 WHERE 子句列作为排序键。您已完成此操作,但将其设置为 salesorderid 之后的第二个排序键。这可能会窃取 datecreated 的所有功能并阻止它提供任何好处。我建议您只使用 salesorderid 作为此排序键,但这是基于查看您的查询中的一个,因此将其视为一组信息不足的建议。这一切都表明,鉴于桌子的尺寸很小,这一切都不太可能产生很大的不同。这里没有足够的数据来让这些键产生巨大的影响。
【讨论】:
以上是关于为啥一个 group by 的聚合这么慢?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 CROSS APPLY 与列和聚合函数需要 Group by
为啥没有聚合函数的选择列需要成为 MySQL 中 Group by 子句的一部分?