【问题标题】:Use Redshift Copy command to do a merge使用 Redshift Copy 命令进行合并
【发布时间】:2016-06-10 09:08:21
【问题描述】:

我有一个迭代输入并将数据输出到 AWS Firehose 的过程,我已将其配置为上传到我创建的红移表。一个问题是,有时行可能会重复,因为该过程需要重新评估数据。 比如:

Event_date, event_id, event_cost
2015-06-25, 123, 3
2015-06-25, 123, 4

http://docs.aws.amazon.com/redshift/latest/dg/t_updating-inserting-using-staging-tables-.html

看看那里,我想用新值替换旧行,比如:

insert into event_table_staging  
select event_date,event_id, event_cost from <s3 location>;

delete from event_table  
using event_table_staging  
where event_table.event_id = event_table_staging.event_id;

insert into target 
select * from event_table_staging;

delete from event_table_staging  
select * from event_table_staging;

是否可以这样做:

Redshift columns: event_date,event_id,cost
copy event_table from <s3> 
(update event_table 
select c_source.event_date,c_source.event_id,c_source.cost from <s3 source> as c_source join event_table on c_source.event_id = event_table.event_id) 
CSV


copy event_table from <s3> 
(insert into event_table 
select c_source.event_date,c_source.event_id,c_source.cost from event_table left outer join<s3 source> as c_source join on c_source.event_id = event_table.event_id where c_source.event_id is NULL) 
CSV

【问题讨论】:

    标签: amazon-web-services amazon-redshift amazon-kinesis-firehose


    【解决方案1】:

    您不能直接从 COPY 进行合并。

    但是,您的初始方法可以使用临时表封装在事务中,以暂存负载数据以获得最佳性能。

    BEGIN
    ;
    CREATE TEMP TABLE event_table_staging (
         event_date  TIMESTAMP  NULL
        ,event_id    BIGINT     NULL
        ,event_cost  INTEGER    NULL )
    DISTSTYLE KEY
    DISTKEY (event_id)
    SORTKEY (event_id)
    ;
    COPY event_table_staging  
    FROM <s3 location>
    COMPUDATE ON
    ;
    UPDATE event_table  
    SET    event_date = new.event_date
          ,event_cost = new.event_cost
    FROM        event_table         AS trg
    INNER JOIN  event_table_staging AS new
            ON  trg.event_id = new.event_id
    WHERE COALESCE(trg.event_date,0) <> COALESCE(new.event_date,0)
      AND COALESCE(trg.event_cost,0) <> COALESCE(new.event_cost,0)
    ;
    INSERT INTO event_table 
    SELECT  event_date
           ,event_id  
           ,event_cost
    FROM        event_table_staging AS new
    LEFT JOIN   event_table         AS trg
           ON   trg.event_id = new.event_id
    WHERE trg.event_id IS NULL
    ;
    COMMIT
    ;
    

    只要您使用事务并且总更新量相对较低(个位数百分比),这种方法实际上表现得非常好。唯一需要注意的是,您的目标需要定期VACUUMed - 每月一次对我们来说就足够了。

    我们每小时对几亿行范围内的几张表执行此操作,即将数亿行合并为数亿行。对合并表的用户查询仍然表现良好。

    【讨论】:

    • 我不能一次性完成,因为输入是 Firehose 流。我不需要每小时拉动,只需要 EOD,这就是我要为其配置 Lambda 或 Datapipeline 作业的目的(仍在决定是否需要基于事件的执行)
    • 性能的重要部分是什么?为什么使用事务和临时表很重要?如果暂存表相当大,那么我假设临时表不会在内存中(或分布在内存中?)并且将类似于永久表在磁盘上。我一直在使用 AWS DMS 工具从 Postgres 同步到 Redshift,并且 RS 集群上的绝大多数使用是 DMS 更新作业,只是试图跟上。我注意到它虽然没有创建正确类型的阶段表,但一切都是一个宽字符串,并且合并/upsert 是作为一个长 case 语句完成的。它经常滞后到死亡
    • AWS DMS 使用此模式从暂存表中合并每一列:"colname"= CASE WHEN "public"."awsdms_changesLONGUUIDHERE"."col1" IS NULL THEN "public"."target_table"."colname" WHEN "public"."awsdms_changesLONGUUIDHERE"."col1" = '&lt;att_null&gt;' THEN NULL ELSE CAST ( "public"."awsdms_changesLONGUUIDHERE"."col1" as INT4) END 请注意已删除数据的神奇值 &lt;att_null&gt; 以及从宽字符串 (varchar(65535) 转换为正确的数据类型) ) 暂存表中的列。这并不快。不过,它使用来自 S3 direct 的副本来分离插入,速度很快。
    【解决方案2】:

    Redshift 已针对以经济高效的方式处理大量数据进行了优化,您需要改变对其他数据库的数据和数据库的一些想法。

    主要概念是您不应该在 Redshift 中更新数据。您应该将 Redshift 中的数据视为“日志”。您可以将函数用作 INSERT 或 UPDATE,但它们会极大地限制您可以处理的数据量。

    您可以通过多种方式处理重复:

    • 您可以通过管理您正在处理的所有 ID 的一些内存查找表(例如在 Redis 中 ElastiCache)来防止写入重复,如果您已经处理过则忽略记录它

    • 您可以在 Redshift 中保留重复记录,并使用 WINDOW 函数处理这些记录,该函数将只获取其中一条记录(例如 LAST_VALUE)。

    • 您可以在 Redshift 中获取原始事件并在对数据库的查询中进行聚合,而不是将其作为预处理进行。此模式还可以灵活地更改聚合数据的方式。通过这些聚合,Redshift 可以非常快,并且几乎不需要预聚合。

    如果您仍想在 Redshift 中拥有“干净”和聚合的数据,您可以 UNLOAD 使用具有正确聚合或 WINDOW 函数的一些 SQL 查询来删除旧表并将数据复制回 Redshift。

    【讨论】:

    • 谢谢,我添加了一个标识列,以便区分 event_id。我将创建一个单独的表,只存储最新更新的结果。
    • 我真的不同意 UPDATE/INSERT/DELETE 在 Redshift 中单方面不好。这些命令得到完全支持并且有据可查。我们使用这些命令在 Redshift 中每小时合并 数百万 行,没有任何问题。
    • 也完全没有必要执行UNLOAD 并重新加载到同一个数据库INSERT INTOCREATE TABLE … AS 就是为了这个目的而存在的。
    • 在这种情况下,我不打算卸载或窗口函数。我确实计划在流端使用 ElastiCache。我的解决方案将流入一个带有 autoid 列的临时表。由于我从 event_date 中分离出来,我将创建一个单独的加载步骤来执行实际的 EOD 合并,它将获取最新值并清理历史数据。
    • 我刚刚意识到我的解决方案更接近您的...我不接受并接受您的解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 2017-11-09
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    相关资源
    最近更新 更多