Redshift中的高效ETL Upsert

时间:2017-08-31 22:34:19

标签: database amazon-web-services amazon-redshift etl upsert

我在从OLTP环境到Redshift的ETLing可更新表中遇到性能问题。我们的基本工作流程是典型的OLTP-> S3-> Redshift数据流。假设我想ETL像这样的表

create table source_data (
id int primary key,
status varchar,
value decimal(10,4),
dateLastTouched datetime,
dateCreated datetime,
index datelasttouched_index (dateLastTouched));

到Redshift中的类似表格。在准备ETL时,我创建了排序键dateLastTouched和dist键id。在上一个作业的最大dateLastTouched ETLd之后,我们ETL具有dateLastTouched的任何记录。

对于没有更新旧记录的表(例如去年的记录改变其状态),此设置非常有效,但是当您添加该功能时,我无法有效地看到ETL。我们目前的做法是:

  1. 使用dateLastTouched将所有新记录或更新记录发送到S3。
  2. 将S3中的数据复制到临时表中。
  3. 从目标表中删除与新数据具有相同主键的所有记录。
  4. 从登台表中插入所有记录。
  5. 鉴于我们使用dateLastTouched设置排序键,步骤3非常慢。通常需要1-2分钟,并且随着时间的推移非常明显地需要更长时间。我们无法将排序键更改为主键,因为我们需要dateLastTouched来报告在表上频繁运行的查询。 我们考虑过的一些想法:

    1. id和dateLastTouched的交叉排序键。我们在另一张桌子上试过这个并且性能提升并不显着。真空重铸时间也很糟糕。
    2. 不要删除,只需插入并使周期性作业将“每个id的最新记录”实现到另一个表。这并不理想,因为它实际上会使大桌子占用的空间翻倍,而且更新频率也不高。
    3. 从S3到Redshift的高效upsert是否有更好的范例?或者我只需要吃掉ETL /物化视图成本?

1 个答案:

答案 0 :(得分:3)

另一种选择是拥有2个版本的表,一个用于用于ETL的dateLastTouched,另一个用于用于报告的order by。当ETL过程在第一个上完成时,您只需重新创建第二个(不使用truncate t2,而只使用insert into t2 select * from t1vacuum reindex t2CREATE FUNCTION dbo.tfn_Tally /* ============================================================================ 07/20/2017 JL, Created. Capable of creating a sequense of rows ranging from -10,000,000,000,000,000 to 10,000,000,000,000,000 ============================================================================ */ ( @NumOfRows BIGINT, @StartWith BIGINT ) RETURNS TABLE WITH SCHEMABINDING AS RETURN WITH cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)), -- 10 rows cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b), -- 100 rows cte_n3 (n) AS (SELECT 1 FROM cte_n2 a CROSS JOIN cte_n2 b), -- 10,000 rows cte_n4 (n) AS (SELECT 1 FROM cte_n3 a CROSS JOIN cte_n3 b), -- 100,000,000 rows cte_Tally (n) AS ( SELECT TOP (@NumOfRows) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) + @StartWith FROM cte_n4 a CROSS JOIN cte_n4 b -- 10,000,000,000,000,000 rows ) SELECT t.n FROM cte_Tally t; GO

此外,根据表的大小和群集的配置,实际上可以更快地重新加载表的整个主体而不需要处理upsert