我有一个ETL流程,该流程正在RedShift中逐步构建维度表。它按以下顺序执行操作:
个别地,此过程有效,但是为了实现连续流刷新foo并在发生故障时实现冗余,我同时运行了该过程的多个实例。当发生这种情况时,我偶尔会遇到并发序列化错误。这是因为这两个过程都重播一些相同的变化foo来自foo_staging于重叠的交易。
foo
foo_staging
发生的是,第一个进程创建了staging_foo表,而第二个进程试图创建具有相同名称的表(这就是我想要的)时被阻止。当第一个进程提交其事务时(可能需要几秒钟),我发现第二个进程在提交完成之前就已解除阻塞。因此,foo在落实提交之前,它似乎正在获取表的快照,这将导致插入/更新/删除(其中一些可能是多余的)失败。
staging_foo
我根据文档http://docs.aws.amazon.com/redshift/latest/dg/c_serial_isolation.html进行理论化,其中说:
并发交易是彼此看不见的;他们无法检测到彼此的变化。每个并发事务将在事务开始时创建数据库的快照。在大多数SELECT语句,DML命令(例如COPY,DELETE,INSERT,UPDATE和TRUNCATE)以及以下DDL命令的第一次出现时,将在事务内创建数据库快照: ALTER TABLE(添加或删除列) 创建表 滴台 截断表
并发交易是彼此看不见的;他们无法检测到彼此的变化。每个并发事务将在事务开始时创建数据库的快照。在大多数SELECT语句,DML命令(例如COPY,DELETE,INSERT,UPDATE和TRUNCATE)以及以下DDL命令的第一次出现时,将在事务内创建数据库快照:
ALTER TABLE(添加或删除列)
创建表
滴台
截断表
上面引用的文档使我有些困惑,因为它首先说将在事务开始时创建快照,但随后说仅在某些特定DML / DDL操作第一次出现时才创建快照。
我不想在我要替换的地方做一个深层副本,foo而不是逐步更新它。我还有其他进程会不断查询此表,因此永远不会有任何时间可以不间断地替换它。另一个问题针对深层复制提出了类似的问题,但它对我不起作用:如何确保对要替换的表进行同步DDL操作?
有没有一种方法可以避免并发序列化错误来执行我的操作?我需要确保可以进行读取访问,foo所以我不能使用LOCK该表。
LOCK
好的,Postgres(以及Redshift [或多或少])使用MVCC(多版本并发控制)来进行事务隔离,而不是使用db / table / row / page锁定模型(如SQL Server,MySQL等所示)。简单地说,每个事务都将根据 事务开始时存在 的数据进行操作。
因此,您的注释“我同时有多个流程实例”说明了问题所在。如果在运行流程1的同时启动流程2,则流程2无法看到流程1的结果。