Redshift EXPLAIN执行计划解析与查询优化咨询
Redshift查询执行计划解析与优化问题
查询语句
SELECT (TO_CHAR(DATE_TRUNC('second', CONVERT_TIMEZONE('GMT', 'UTC', "ABC"."time")), 'YYYY-MM-DD HH24:MI:SS')) AS "rtime", COUNT(DISTINCT ABC.s) AS "s" FROM ABC INNER JOIN TE ON "ABC"."e_id" = "TE"."e_id" WHERE "TE"."e_code" = 'ABCDE' GROUP by 1 ORDER BY 1
执行计划
XN Merge (cost=1000000944628.86..1000000944629.36 rows=200 width=200) Merge Key: resp -> XN Network (cost=1000000944628.86..1000000944629.36 rows=200 width=200) Send to leader -> XN Sort (cost=1000000944628.86..1000000944629.36 rows=200 width=200) Sort Key: resp -> XN HashAggregate (cost=944620.71..944621.21 rows=200 width=200) -> XN Subquery Scan volt_dt_0 (cost=944506.75..944606.47 rows=2849 width=200) -> XN HashAggregate (cost=944506.75..944577.98 rows=2849 width=29) -> XN Hash Join DS_DIST_ALL_NONE (cost=132.60..944492.51 rows=2849 width=29) Hash Cond: (((("outer".context_id)::text || ':'::text) || ("outer".e_id)::text) = ("inner".e_id)::text) -> XN Seq Scan on ABC (cost=0.00..151081.63 rows=15108163 width=33) -> XN Hash (cost=132.60..132.60 rows=2 width=17) -> XN Seq Scan on te (cost=0.00..132.60 rows=2 width=17) Filter: ((e_code)::text = 'ABCDE'::text)
表结构配置
- ABC表:
DISTSTYLE EVEN SORTKEY ( inserted_datetime );
- TE表:
DISTSTYLE ALL SORTKEY ( e_id );
问题解答
1. 是ORDER子句还是Sequence Scan导致性能问题?
主要性能瓶颈是ABC表的全表扫描(Seq Scan):ABC表有1500多万行数据,全表扫描需要遍历所有节点上的该表数据,这是40秒耗时的核心来源。而ORDER BY对应的排序操作仅针对最终200行结果,实际耗时可以忽略,执行计划中高cost是因为叠加了数据传输到leader节点的估算开销,并非实际排序的耗时。
解决Seq Scan的方案:
- 调整ABC表的排序键,添加
e_id作为前缀(比如SORTKEY (e_id, inserted_datetime)),这样可以利用排序键的前缀过滤,只扫描与TE表匹配的e_id对应的数据块,减少扫描量; - 如果业务允许,将ABC表的分布键改为
e_id,避免关联时的数据跨节点传输,但需评估对其他查询的影响; - 确保表统计信息是最新的,执行
ANALYZE ABC;让优化器生成更准确的执行计划。
2. 是否可以认为cost值越高,执行时间越长?
不完全是。Redshift的cost是基于统计信息的估算值,不是实际执行时间的精确映射:
- 执行计划中
XN Merge和XN Sort的cost最高,但处理的仅为200行数据,实际耗时极低; - ABC表的Seq Scan cost看似低,但处理1500多万行数据,实际耗时占比最高。
判断性能瓶颈需结合rows列显示的实际处理行数,而非仅看cost值。
3. 为何使用'XN Hash Join DS_DIST_ALL_NONE'而非EVEN分布风格?
DS_DIST_ALL_NONE是Redshift根据两表分布策略选择的最优连接方式:
- TE表是
DISTSTYLE ALL,每个计算节点都有完整的TE表副本; - ABC表是
DISTSTYLE EVEN,数据均匀分布在各节点;
这种情况下,每个节点可以直接用本地的TE副本与本地的ABC数据做哈希连接,无需移动任何表的数据,DS_DIST_ALL_NONE正是描述这种“无需重分布”的连接策略,和两表的分布风格直接相关。
4. 为何此处使用Subquery Scan?
这是Redshift优化器的内部实现细节:因为查询使用了COUNT(DISTINCT ABC.s),优化器会先执行一次HashAggregate完成去重计算,生成中间结果集;Subquery Scan volt_dt_0就是用来临时扫描这个中间结果集的步骤,为外层的最终聚合做准备,属于优化器自动生成的逻辑,不需要手动调整。
内容的提问来源于stack exchange,提问作者Tyash
相关产品推荐
相关产品推荐

