我正在准备旧版 PostgreSQL 9.5 数据库进行升级。
我需要从表中删除 OID,而不需要长时间锁定表。我已经制定了一个似乎有效的策略,但我希望专家能够参与进来,因为我计划对系统表进行一些通常不被允许的操作。
在运行 pg_repack 之前,我执行以下修改:
mydata=# update pg_class set relhasoids = false where oid = 'some_schema.a_very_large_table_with_oids'::regclass;
UPDATE 1
mydata=# delete from pg_attribute where attrelid = 'some_schema.a_very_large_table_with_oids'::regclass and attname = 'oid';
DELETE 1
mydata=# \d+ some_schema.a_very_large_table_with_oids;
Table "some_schema.a_very_large_table_with_oids"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------+-----------+----------+--------------+-------------
k | text | not null | extended | |
v | text | | extended | |
Indexes:
"a_very_large_table_with_oids_pkey" PRIMARY KEY, btree (k)
mydata=# select oid,* from some_schema.a_very_large_table_with_oids;
ERROR: column "oid" does not exist
到目前为止一切顺利。我可以插入更新和删除行,但磁盘上的表结构没有改变。我需要解决这个问题。
因此,在进行这些修改后,我使用 vanilla pg_repack 重新打包表。这会将数据复制到磁盘上的新表中,无需任何 oid。
在我开始对生产数据在线执行这些操作之前,我希望有一些专家关注这个过程,因为这是关键任务。
在非常大的表上,我们将在很长一段时间内处于这种不确定状态,其中 pg_class 和 pg_attribute 将进行强制修改,而 pg_repack 发挥其魔力。
如果插入/更新/删除似乎有效,有什么需要担心的吗?
在 pg_repack 运行时我在表上的插入/更新/删除似乎工作正常。
我还在附有烤面包桌的桌子上尝试过这个。乍一看一切似乎都井然有序。
这是一个破坏性操作,我没有使用规范的
ALTER TABLE ... SET WITHOUT OIDS
。如果我遗漏了一些细节(例如在备份恢复或复制期间),我想确保我不会给自己带来问题。
请指教。
您想避免表重写,对吗?
您正在做的事情相当于 PostgreSQL 在
commit 6d1e361852之前对
ALTER TABLE ... SET WITHOUT OIDS
所做的事情,除了您忘记在表上加 ACCESS EXCLUSIVE
锁,并且您不会使其他计划和缓存的元数据信息无效。会话有此表。
现在有一个原因,
ALTER TABLE ... SET WITHOUT OIDS
被更改重写表格;请参阅此错误报告和此后续线程中的讨论。那里提到的问题在 pg_upgrade
之后不会影响您,但是如果您的表的元组中物理上有 OID,而 PostgreSQL 不希望有任何 OID,则可能会出现其他微妙的问题。这就是为什么ALTER TABLE ... SET WITHOUT OIDS
被更改以重写表格的原因。
您期望运行 pg_repack 会物理上删除元组中剩余的 OID,但它不会,就像
VACUUM (FULL)
不会一样。两者都只是按原样复制现有元组。您必须执行类似 INSERT INTO newtab SELECT FROM oldtab
之类的操作,这将消除 oldtab
中的物理 OID,但相当于您想要避免的表重写。
您的目录操作将使表处于类似于 PostgreSQL 8.3 及更早版本中的
ALTER TABLE ... SET WITHOUT OIDS
的状态。现在 pg_upgrade
文档提到 9.2 及更高版本支持升级,并且在 commit e469f0aaf3 之前提到支持 8.4 及更高版本。虽然历史文档中没有明确提及以您的方式删除 OID 的表会构成问题,但这种情况显然是意外的,根本没有经过测试并且不受支持。您将来可能会遇到有趣的问题。我当然不会为我的数据库冒这个风险。
为了安全起见,通过重写表来正确删除 OID。