为了给出一些上下文,命令在任务中发出,许多任务可能同时从多个worker发出相同的命令。
每个任务都尝试创建一个postgres架构。我经常收到以下错误:
initial begin for (IR = 0; IR <= 65535; IR++); $finish; end
Postgres版本是PostgreSQL 9.4rc1 这是Postgres的一个错误吗?
答案 0 :(得分:12)
对于表和模式的IF NOT EXISTS
的实现,这有点蠢。基本上,他们是一个upsert尝试,而PostgreSQL并没有干净地处理竞争条件。这很安全,但很难看。
如果架构是在另一个会话中同时创建但尚未提交,则它既存在又不存在,具体取决于您是谁以及您的外观。其他交易不可能&#34;参见&#34;系统目录中的新架构是因为它未提交,因此pg_namespace
中的条目对其他事务不可见。因此,CREATE SCHEMA
/ CREATE TABLE
会尝试创建它,因为就其而言,该对象并不存在。
但是,将行插入具有唯一约束的表中。唯一约束必须能够查看未提交的行才能运行。因此插入阻塞(停止)直到执行CREATE
的第一个事务提交或回滚。如果它提交,则第二个事务中止,因为它试图插入违反唯一约束的行。 CREATE SCHEMA
并不够聪明,无法抓住这个案例并重新尝试。
要正确修复此PostgreSQL可能需要谓词锁定,它可以锁定行的潜力。这可能会作为当前正在进行的实施UPSERT
的工作的一部分添加。
对于这些特定命令,PostgreSQL可能会执行系统目录的脏读,在那里可以看到未提交的更改。然后它可以等待未提交的事务提交或回滚,重新执行脏读以查看是否有其他人正在等待,然后重试。但这会产生竞争条件,其他人可能会在您执行读取操作以及尝试创建它时之间创建架构。
所以IF NOT EXISTS
变种必须:
据我所知,没有人实施,或者他们尝试过,但它并没有被接受。使用这种方法可能会出现事务ID刻录率等问题。
我认为这是一个各种各样的错误,但它是一个&#34;是的,我们知道&#34;一种错误,而不是一种&#34;我们会正确地解决这个问题&#34;那种虫子。随意发布关于它的pgsql-bugs;至少文档应该提到关于IF NOT EXISTS
的这个警告。
我不建议同时做DDL。
答案 1 :(得分:1)
我需要在同时创建模式的应用程序中解决此限制。对我有用的是添加
ws
在包含LOCK TABLE pg_catalog.pg_namespace
的交易中。看起来像一个肮脏和不安全的事情,但帮助我解决了只在测试中发生的问题。