Redshift 可以使用子查询的结果来按 sortkey 过滤吗?

Posted

技术标签:

【中文标题】Redshift 可以使用子查询的结果来按 sortkey 过滤吗?【英文标题】:Can Redshift use the results of a subquery to filter by sortkey? 【发布时间】:2017-03-21 21:20:27 【问题描述】:

我在 Redshift 中有一个包含数十亿行的表,看起来像这样

CREATE TABLE channels AS (
 fact_key TEXT NOT NULL distkey
 job_key BIGINT
 channel_key TEXT NOT NULL
)
diststyle key
compound sortkey(job_key, channel_key);

当我通过 job_key + channel_key 查询时,如果我在查询中使用 channel_key 的特定值,我的 seq 扫描会受到完整排序键的适当限制。

EXPLAIN
SELECT * FROM channels scd
WHERE scd.job_key = 1 AND scd.channel_key IN ('1234', '1235', '1236', '1237')

XN Seq Scan on channels scd  (cost=0.00..3178474.92 rows=3428929 width=77)
  Filter: ((((channel_key)::text = '1234'::text) OR ((channel_key)::text = '1235'::text) OR ((channel_key)::text = '1236'::text) OR ((channel_key)::text = '1237'::text)) AND (job_key = 1))

但是,如果我使用 IN + 查询 channel_key,Redshift 不会使用排序键。

EXPLAIN
SELECT * FROM channels scd
WHERE scd.job_key = 1 AND scd.channel_key IN (select distinct channel_key from other_channel_list where job_key = 14 order by 1)

XN Hash IN Join DS_DIST_ALL_NONE  (cost=3.75..3540640.36 rows=899781 width=77)
  Hash Cond: (("outer".channel_key)::text = ("inner".channel_key)::text)
  ->  XN Seq Scan on channels scd  (cost=0.00..1765819.40 rows=141265552 width=77)
        Filter: (job_key = 1)
  ->  XN Hash  (cost=3.75..3.75 rows=1 width=402)
        ->  XN Subquery Scan "IN_subquery"  (cost=0.00..3.75 rows=1 width=402)
              ->  XN Unique  (cost=0.00..3.74 rows=1 width=29)
                    ->  XN Seq Scan on other_channel_list  (cost=0.00..3.74 rows=1 width=29)
                          Filter: (job_key = 14)

是否有可能让它工作?我的最终目标是把它变成一个视图,这样预先定义我的 channel_keys 列表就行不通了。

编辑以提供更多上下文:

这是一个更大的查询的一部分,这个查询的结果与其他一些数据相结合。如果我对 channel_keys 进行硬编码,那么散列连接的输入约为 200 万行。如果我在子查询中使用 IN 条件(没有其他变化),那么哈希连接的输入是 4 亿行。总查询时间从约 40 秒到 15 分钟以上。

【问题讨论】:

如果IN 只返回四个值,性能会有什么不同吗? @JohnRotenstein 不,我尝试将“LIMIT 4”放入子查询并获得相同的查询计划 但是忽略查询计划,如果IN 返回的值与没有IN 的版本相同,那么使用IN 的查询本身是否需要更长的时间? (不要使用LIMIT 伪造它——比较匹配查询的实际结果以了解性能是否不同。) @JohnRotenstein 是的,我在原始帖子中添加了快速编辑。这是更大查询的一部分。如果没有子查询,过滤器会在哈希连接之前应用,这会导致大约 2m 行作为哈希连接的输入。对于子查询,过滤器在哈希连接之后应用,并导致大约 4 亿行进入哈希连接。 【参考方案1】:

这给你一个比子查询版本更好的计划吗?

with other_channels as (
    select distinct channel_key from other_channel_list where job_key = 14 order by 1
)
SELECT *
FROM channels scd
JOIN other_channels ocd on scd.channel_key = ocd.channel_key
WHERE scd.job_key = 1

【讨论】:

遗憾的是,无论是查询计划还是执行时间,都没有区别。在我的主查询中的哈希连接之前,channel_key 上的过滤器仍然没有发生

以上是关于Redshift 可以使用子查询的结果来按 sortkey 过滤吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Redshift 不支持 DOES EXIST 相关子查询?

Oracle 到 Redshift 查询

如何在 Redshift Query 中禁用使用缓存结果?

使用 case when 时出现 SQL (Redshift) 错误 - 不支持这种类型的相关子查询模式

Redshift 相关子查询内部错误

定期将查询结果从 Redshift 移动到 S3 存储桶