Amazon web services 将数据从AmazonS3复制到Redshift并避免重复行

Amazon web services 将数据从AmazonS3复制到Redshift并避免重复行,amazon-web-services,amazon-s3,duplicates,copy,amazon-redshift,Amazon Web Services,Amazon S3,Duplicates,Copy,Amazon Redshift,我正在将数据从AmazonS3复制到Redshift。在此过程中,我需要避免再次加载相同的文件。我的红移表上没有任何唯一的约束。有没有办法使用copy命令实现这一点 我尝试添加唯一约束并将列设置为主键,但没有成功。红移似乎不支持唯一/主键约束。目前无法从红移中删除重复项。Redshift不支持主键/唯一键约束,并且使用行编号删除重复项也不是一个选项删除行编号大于1的行,因为Redshift上的删除操作不允许复杂语句,而且Redshift中不存在行编号的概念 删除重复项的最佳方法是编写cron/q

我正在将数据从AmazonS3复制到Redshift。在此过程中,我需要避免再次加载相同的文件。我的红移表上没有任何唯一的约束。有没有办法使用copy命令实现这一点


我尝试添加唯一约束并将列设置为主键,但没有成功。红移似乎不支持唯一/主键约束。

目前无法从红移中删除重复项。Redshift不支持主键/唯一键约束,并且使用行编号删除重复项也不是一个选项删除行编号大于1的行,因为Redshift上的删除操作不允许复杂语句,而且Redshift中不存在行编号的概念

删除重复项的最佳方法是编写cron/quartz作业,该作业将选择所有不同的行,将它们放在单独的表中,然后将该表重命名为原始表

插入到temp_Originatable中,选择与Originatable不同的选项

升降台原件


将表temp_originalTable rename改为originalTable

正如user1045047所提到的,Amazon Redshift不支持唯一约束,因此我一直在寻找使用delete语句从表中删除重复记录的方法。 最后,我找到了一个合理的方法

Amazon Redshift支持创建一个标识列,该列存储一个自动生成的唯一编号。

以下sql用于PostgreSQL删除OID为唯一列的重复记录,您可以通过将OID替换为标识列来使用此sql

DELETE FROM duplicated_table WHERE OID > (
 SELECT MIN(OID) FROM duplicated_table d2
  WHERE column1 = d2.dupl_column1
  AND column2 = d2.column2
);
下面是我在Amazon Redshift集群上测试的一个示例

create table auto_id_table (auto_id int IDENTITY, name varchar, age int);

insert into auto_id_table (name, age) values('John', 18);
insert into auto_id_table (name, age) values('John', 18);
insert into auto_id_table (name, age) values('John', 18);
insert into auto_id_table (name, age) values('John', 18);
insert into auto_id_table (name, age) values('John', 18);
insert into auto_id_table (name, age) values('Bob', 20);
insert into auto_id_table (name, age) values('Bob', 20);  
insert into auto_id_table (name, age) values('Matt', 24); 

select * from auto_id_table order by auto_id; 
 auto_id | name | age 
---------+------+-----
       1 | John |  18
       2 | John |  18
       3 | John |  18
       4 | John |  18
       5 | John |  18
       6 | Bob  |  20
       7 | Bob  |  20
       8 | Matt |  24    
(8 rows) 

delete from auto_id_table where auto_id > (
  select min(auto_id) from auto_id_table d
    where auto_id_table.name = d.name
    and auto_id_table.age = d.age
);

select * from auto_id_table order by auto_id;
 auto_id | name | age 
---------+------+-----
       1 | John |  18
       6 | Bob  |  20
       8 | Matt |  24
(3 rows)
它还可以像这样使用COPY命令

auto_id_table.csv

John,18
Bob,20
Matt,24
复制sql

copy auto_id_table (name, age) from '[s3-path]/auto_id_table.csv' CREDENTIALS 'aws_access_key_id=[your-aws-key-id] ;aws_secret_access_key=[your-aws-secret-key]' delimiter ','; 
这种方法的优点是不需要运行DDL语句。但是,它不适用于没有标识列的现有表,因为无法将标识列添加到现有表中。使用现有表删除重复记录的唯一方法是像这样迁移所有记录。与user1045047的答案相同

insert into temp_table (select distinct from original_table);
drop table original_table;
alter table temp_table rename to original_table;

我的解决方案是在表上“复制”之前运行“删除”命令。在我的用例中,每次我需要将每日快照的记录复制到redshift表中,因此我可以使用以下“delete”命令来确保删除重复的记录,然后运行“copy”命令

从t_数据中删除,其中快照_日期='xxxx xx'

不直接将数据加载到主表怎么样

避免重复的步骤:

开始交易 批量加载到临时暂存表中 从主表中删除,其中行=暂存表行 从暂存表合并插入主表 投料台 结束交易。
这也有点快,红移文档推荐使用。

我们每周删除重复项,但您也可以在加载事务期间执行此操作,如@Kyle所述。此外,这确实需要存在一个自动生成的ID列作为删除的最终目标:

DELETE FROM <your table> WHERE ID NOT IN ( 
   SELECT ID FROM (
      SELECT *, ROW_NUMBER() OVER 
         ( PARTITION BY <your constraint columns> ORDER BY ID ASC ) DUPLICATES 
      FROM REQUESTS 
   ) WHERE DUPLICATES=1
); COMMIT; 

我使用了类似的解决方案。在向表中添加新记录时,我们无法实现这一点。在插入表之前,我们首先检查了该表。如果存在记录,我们将在插入前删除该行。您是否考虑过使用事务?我不清楚您的复制sql如何指示它正确处理重复项。对于正在加载的数据集audo_id_table.csv,它只有3个唯一的行,不是吗?关键是您可以轻松删除重复记录。即使您运行“复制自动\u id\u表”三次并获得三条重复记录,这些重复记录也将使用上面的“从自动\u id\u表中删除”来删除。。。。使用这种方法,您需要运行命令吗?我读到:如果您使用多个并发复制命令从多个文件加载一个表,Amazon Redshift将被迫执行序列化加载,如果表定义了排序列,则加载速度要慢得多,并且需要在最后有一个真空。运行真空和分析之后效果更好,但这不是必需的,因为真空会带来一些成本。在我的例子中,由于重复记录的数量很少,我计划每天运行一次吸尘器,因此我不使用此查询来运行它。您能详细说明一下这个答案中的这也是超快速部分吗?我们有一个数十亿行的表,我们使用Amazon文档推荐的方法,但是除非我们做错了什么,否则它肯定不是超快速的。到目前为止,这是我们ETL过程的瓶颈。我想超快是相当主观的。我只做过数百万行的工作,没有几十亿行……但没有比这更快的过程来确保没有我听说过的重复记录。有兴趣听听你们是否有什么问题,这是当暂存表有重复的记录时。是的,如果暂存表有重复的记录 您将插入重复的行。我们所要做的是编写合并sql时要牢记这一点……或多或少地按组合键分组,并执行任何必要的聚合或第一个值,以避免在插入时重复。
CREATE TABLE IF NOT EXISTS public.requests
(
    id BIGINT NOT NULL DEFAULT "identity"(1, 0, '1,1'::text) ENCODE delta
    kaid VARCHAR(50)   NOT NULL 
    ,eid VARCHAR(50)   NOT NULL ENCODE text32k
    ,aid VARCHAR(100)  NOT NULL ENCODE text32k
    ,sid VARCHAR(100)  NOT NULL ENCODE zstd
    ,rid VARCHAR(100)  NOT NULL ENCODE zstd
    ,"ts" TIMESTAMP WITHOUT TIME ZONE NOT NULL  ENCODE delta32k
    ,rtype VARCHAR(50) NOT NULL ENCODE bytedict
    ,stype VARCHAR(25)          ENCODE bytedict
    ,sver VARCHAR(50)  NOT NULL ENCODE text255
    ,dmacd INTEGER              ENCODE delta32k
    ,reqnum INTEGER    NOT NULL ENCODE delta32k
    ,did VARCHAR(255)           ENCODE zstd
    ,"region" VARCHAR(10)       ENCODE lzo
)
DISTSTYLE EVEN
SORTKEY (kaid, eid, aid, "ts")
;

. . . 

DELETE FROM REQUESTS WHERE ID NOT IN ( 
   SELECT ID FROM (
      SELECT *, ROW_NUMBER() OVER 
         ( PARTITION BY DID,RID,RTYPE,TS ORDER BY ID ASC ) DUPLICATES 
      FROM REQUESTS 
   ) WHERE DUPLICATES=1
); COMMIT;