在Redshift中执行表交换的最佳实践

时间:2017-09-06 13:54:06

标签: amazon-redshift etl

我们正在Redshift集群上运行一些小时脚本,为数据使用者构建汇总表。在组装临时表之后,该脚本然后运行一个事务,该事务删除现有表并将其替换为临时表,如下所示:

BEGIN;

DROP TABLE IF EXISTS public.data_facts;
ALTER TABLE public.data_facts_stage RENAME TO data_facts;

COMMIT;

此操作的问题在于,长时间运行的分析查询会在public.data_facts上放置一个AccessShareLock,以防止它被丢弃并破坏我们的ETL循环。我在想一个更好的解决方案就是重命名现有的表,如下:

ALTER TABLE public.data_facts RENAME TO data_facts_old;
ALTER TABLE public.data_facts_stage RENAME TO data_facts;
DROP TABLE public.data_facts_old;

然而,这种方法预先假定1)public.data_facts存在,并且2)public.data_facts_old不存在。

您是否知道是否有办法在SQL中安全地执行此操作,而不依赖于应用程序逻辑? (例如像ALTER TABLE IF EXISTS这样的东西)。

2 个答案:

答案 0 :(得分:1)

您可以向目标表添加新的load time timestamp encode runlength default getdate()列,并使ETL执行此操作:

INSERT INTO public.data_facts
SELECT * FROM public.data_facts_staging;
DELETE FROM public.data_facts
WHERE load_time<(select max(load_time) from public.data_facts);
DROP TABLE public.data_facts_staging;

注意:public.data_facts_staging应与public.data_facts具有完全相同的结构,但public.data_facts的最后一列为load_time,因此在插入时,它将填充当前时间戳。

唯一的含义是,在插入新行和删除旧行之间需要额外的磁盘空间,而load_time必须始终是最后一列。每次执行此操作时,您还必须vaccum表。

另一个好处是,如果您的ETL失败并且登台表为空或没有登台表,您将不会丢失数据。在使用DDL交换表的纯SQL方案中,当缺少登台表时,您不会受到保护而不会丢弃目标表。在建议的场景中,如果没有插入新行,则delete语句不会删除任何内容(没有小于最大加载时间的行),因此最坏的情况是只有旧版本的数据。

P.S。有一个命令,而不是insert ... select ...只是将指针从登台更改为目标表(alter table ... append from ...),但它需要与alter table相同类型的锁定,我想,所以我不会&#39 ;建议这个

答案 1 :(得分:1)

我还没有尝试过,但看着the documentation of CREATE VIEW,似乎可以通过后期绑定视图来完成。

主要想法是用户与之交互的视图public.data_facts。在幕后,您可以加载新数据,然后交换视图以“指向”新表。

<强>自举

-- load data into public.data_facts_v0
CREATE VIEW public.data_facts AS
SELECT * from public.data_facts_v0 WITH NO SCHEMA BINDING;

<强>更新

-- load data into public.data_facts_v1
CREATE OR REPLACE VIEW public.data_facts AS
SELECT * from public.data_facts_v1 WITH NO SCHEMA BINDING;
DROP TABLE public.data_facts_v0;

WITH NO SCHEMA BINDING表示视图将进行后期绑定。 “在查询视图之前,后期绑定视图不会检查底层数据库对象,例如表和其他视图。”这意味着更新甚至可以引入具有重命名列或全新结构的表。 / p>

注意:

  1. 将交换操作包装到transaction中可能是个好主意,以确保在VIEW交换失败时我们不会删除上一个表。