Fra*_*ova 9 postgresql concurrency ddl catalog
为了给出一些上下文,命令在任务内部发出,许多任务可能同时从多个worker发出相同的命令.
每个任务都尝试创建一个postgres架构.我经常收到以下错误:
Run Code Online (Sandbox Code Playgroud)IntegrityError: (IntegrityError) duplicate key value violates unique constraint "pg_namespace_nspname_index" DETAIL: Key (nspname)=(9621584361) already exists. 'CREATE SCHEMA IF NOT EXISTS "9621584361"'
Postgres版本是PostgreSQL 9.4rc1.
这是Postgres的一个错误吗?
Cra*_*ger 14
这IF NOT EXISTS
对于表和模式的实现来说有点蠢.基本上,它们是一种强烈的尝试,而PostgreSQL并不能完全处理竞争条件.这很安全,但很难看.
如果模式在另一个会话中同时创建但尚未提交,则它既存在又不存在,具体取决于您是谁以及您的外观.其他事务不可能"看到"系统目录中的新模式,因为它是未提交的,因此它的输入pg_namespace
对其他事务是不可见的.所以CREATE SCHEMA
/ CREATE TABLE
尝试创建它,因为就其而言,该对象不存在.
但是,它会将一行插入具有唯一约束的表中.唯一约束必须能够查看未提交的行才能运行.因此插入块(停止)直到执行CREATE
提交或回滚的第一个事务.如果它提交,则第二个事务中止,因为它试图插入违反唯一约束的行.CREATE SCHEMA
是不够聪明,抓住这个案子并重新尝试.
要正确修复这个PostgreSQL可能需要谓词锁定,它可以锁定行的可能性.这可能会作为当前正在进行的工作的一部分添加UPSERT
.
对于这些特定的命令,PostgreSQL可能会对系统目录进行脏读,在那里可以看到未提交的更改.然后它可以等待未提交的事务提交或回滚,重新执行脏读以查看是否有其他人正在等待,然后重试.但是这会有竞争条件,其他人可能会在您执行读取操作以及尝试创建它时之间创建模式.
因此IF NOT EXISTS
变体必须:
据我所知,没有人实施,或者他们尝试过,但是没有被接受.使用这种方法可能会出现事务ID刻录率等问题.
我认为这是一个各种各样的错误,但它是一个"是的,我们知道"的一种错误,而不是"我们会纠正这种错误".随意发布关于它的pgsql-bugs; 至少文档应该提到这个警告IF NOT EXISTS
.
我不建议同时执行DDL.