为什么在RedShift中事务结束之前会释放隐式表锁



我有一个ETL过程,它在RedShift中增量构建维度表。它按以下顺序执行操作:

  1. 开始事务
  2. 创建类似foo的staging_foo表
  3. 将数据从外部源复制到staging_foo
  4. 对foo执行大规模插入/更新/删除,使其与staging_foo匹配
  5. 删除staging_foo
  6. 提交事务

这个进程单独运行,但为了实现对foo的连续流式刷新和故障时的冗余,我有几个进程实例同时运行。当这种情况发生时,我偶尔会遇到并发序列化错误。这是因为两个进程都在重叠事务中从foo_staging重播对foo的一些相同更改。

发生的情况是,第一个进程创建staging_foo表,而第二个进程在尝试创建具有相同名称的表时被阻止(这正是我想要的)。当第一个进程提交其事务时(这可能需要几秒钟),我发现第二个进程在提交完成之前就被解除了阻塞。因此,它似乎在提交到位之前获得了foo表的快照,这会导致插入/更新/删除(其中一些可能是多余的)失败。

我正在根据文件进行推理http://docs.aws.amazon.com/redshift/latest/dg/c_serial_isolation.html上面写着:

并发事务彼此不可见;它们无法检测到彼此的变化。每个并发事务都将在事务开始时创建数据库的快照。当大多数SELECT语句、DML命令(如COPY、DELETE、INSERT、UPDATE和TRUNCATE)以及以下DDL命令首次出现时,会在事务中创建数据库快照:

ALTER TABLE(用于添加或删除列)

创建表

下拉表

截断表

上面引用的文档让我有些困惑,因为它首先说将在事务开始时创建快照,但随后说只有在某些特定DML/DDL操作首次出现时才会创建快照。

我不想做一个深度复制,在那里我替换foo,而不是增量更新它。我有其他进程不断查询这个表,所以我从来没有时间可以不间断地替换它。另一个问题对深度复制提出了类似的问题,但对我来说不起作用:如何确保对正在被替换的表执行同步DDL操作?

有没有一种方法可以让我以避免并发序列化错误的方式执行操作?我需要确保foo的读访问可用,所以我不能LOCK那个表。

好的,Postgres(以及Redshift[或多或少])使用MVCC(多版本并发控制)进行事务隔离,而不是db/table/row/page锁定模型(如SQL Server、MySQL等)。简单地说,每个事务都对事务启动时存在的数据进行操作。

所以你的评论"我有几个进程同时运行的实例"解释了这个问题。如果进程2在进程1运行时启动,则进程2无法看到进程1的结果。

最新更新