12

我正在将数据从 Amazon S3 复制到 Redshift。在此过程中,我需要避免再次加载相同的文件。我的 Redshift 表没有任何独特的限制。有没有办法使用复制命令来实现这一点?

http://docs.aws.amazon.com/redshift/latest/dg/r_COPY_command_examples.html

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

4

6 回答 6

17

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

Amazon Redshift 支持创建存储自动生成的唯一编号的 IDENTITY 列。 http://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html

以下 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;
于 2013-07-11T07:38:41.610 回答
9

嗯..

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

避免重复的步骤:

  1. 开始交易
  2. 批量加载到临时临时表中
  3. 从主表中删除,其中行 = 临时表行
  4. 从临时表插入主表(合并)
  5. 删除临时表
  6. 结束交易。

这也是极好的有点快,由redshift docs推荐。

于 2014-11-26T15:25:30.157 回答
7

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

从 t_data 中删除,其中 snapshot_day = 'xxxx-xx-xx';

于 2013-08-12T15:58:47.310 回答
4

目前没有办法从 redshift 中删除重复项。Redshift 不支持主键/唯一键约束,并且使用行号删除重复项也不是一种选择(删除行号大于 1 的行),因为 redshift 上的删除操作不允许复杂的语句(也是红移中不存在行号)。

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

Insert into temp_originalTable (Select Distinct from originalTable)

Drop table originalTable

Alter table temp_originalTable rename to originalTable

于 2013-06-12T18:21:28.993 回答
0

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

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; 

例如:

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; 
于 2021-03-07T01:26:33.877 回答
0

还有另一种解决方案可以真正避免数据重复,尽管它不像插入后删除重复数据那么简单。复制命令具有清单选项来指定要复制的文件

copy customer
from 's3://mybucket/cust.manifest' 
iam_role 'arn:aws:iam::0123456789012:role/MyRedshiftRole'
manifest; 

您可以在每次运行复制命令之前构建一个生成新清单文件的 lambda。该 lambda 会将已复制的文件与到达的新文件进行比较,并将创建一个仅包含新文件的新清单,这样您就不会两次摄取同一个文件

于 2021-12-21T11:58:03.220 回答