Redshift:将每个查询的结果列链接到 table

Redshift: Chaining resultant columns of each query into a table

我在生产环境中有大约 50 个查询。每个查询 returns 两列 - userid 和一些计算列

要求是所有这些查询都应通过用户 ID 将计算列放入结果 table 中。

例如:-

查询第一个 returns 以下包含数据的列:-

-------------
userid | c1 |
-------------

同样查询第二个:-

-------------
userid | c2 |
-------------

第50条查询:-

-------------
userid | c50 |
-------------

现在,每个查询的计算列输出都应附加到生成的主 table 中,例如:-

--------------------------------------------------
userid | c1 | c2 | c3 |..............| c49 | c50 |
--------------------------------------------------

现在最天真的方法是将每个查询的输出写入一个单独的临时 tables,然后将用户 ID 上的每个 tables 连接到一个结果 table。这个问题我不想通过创建 temp tables 来污染命名空间,因为这是 redshift 并且 tables 真的很大,提交每个 temp table 本身在存储方面会有很大的相关成本。

我想到的下一个解决方案是使用 'with' CTE :-

insert into Resultant
with rel1 as (select userid, c1 from t1 ),
rel2 as (select userid,c2 from t2 ),
.
.
rel50 as (select userid, c50 from t50)
select * from rel1 inner join rel2 on rel1.userid = rel2.userid 
inner join rel3 on rel2.userid = rel3.userid
...
...
inner join rel50 on rel49.userid = rel50.userid

我不知道这个解决方案的优化程度如何。 Redshift docs 提及:-

Where possible, WITH clause subqueries that are referenced multiple times are optimized as common subexpressions; that is, it may be possible to evaluate a WITH subquery once and reuse its results.

另一种方法可能是使用 50 个更新连接 :-

update resultant set resultant.col1 = (select Q.col1 from ("inner query that generates userid and col1) Q inner join resultant on resultant.userid = Q.userid );
update resultant set resultant.col2 = (select Q.col2 from ("inner query that generates userid and col1) Q inner join resultant on resultant.userid = Q.userid );
update resultant set resultant.col50 = (select Q.col50 from ("inner query that generates userid and col1) Q inner join resultant on resultant.userid = Q.userid );

这种方法会产生更多的成本吗?由于 Redshift 是基于列的,我希望它不必更新整行。

有没有比这两种方法更优化的存储过程中执行此操作的方法?理想情况下,如果绝对没有必要,我想避免使用存储过程。 每个查询 returns 大约 ~50GB 的结果集。

有趣的问题。绝对不要沿着更新路径走下去——Redshift 是柱状的,这会使 table.

变得一团糟

加入会起作用,但我也不认为它会很理想。您正在谈论的 JOIN 数量可能会与 Redshift 查询中独立部分的最大数量相冲突。您可以使用 temp tables 来解决这个问题。我仍然认为这不会是很好的表现。数据小的话可能acceptable

我会考虑通过将查询结果与查询标识符联合起来来实现。然后在外部 select 中使用 GROUP BY 构建宽格式。这将创建最少数量的新 table 结构并使用更快的分组方法(比加入)。如果数据量很大,为具有 userid 分布键的 UNION 结果创建临时 table 是有意义的。这将允许 GROUP BY 操作 运行 slice-local 与需要重新分配数据。制作temp的开销table只有数据量大才会抵消

UNION 输出类似于:

userid | queryid | value

然后是这样的查询:

select userid, min(decode(queryid, 1, value)) as c1, min(decode(queryid, 2, value)) as c2, ...
from union_data
group by userid;

我希望这比您概述的任何一种方法都快,但可能还有更好的方法。