【问题标题】:Remove "identity flag" from a column in PostgreSQL从 PostgreSQL 的列中删除“身份标志”
【发布时间】:2022-01-21 16:09:00
【问题描述】:

我在 PostgreSQL 12.9 中有一些表被声明为类似

-- This table is written in old style
create table old_style_table_1 (
    id bigserial not null primary key,
    ...
);

-- This table uses new feature
create table new_style_table_2 (
    id bigint generated by default as identity,
    ...
);

第二个表似乎是使用第 10 版中引入的identity flag 声明的。

时间过去了,我们已经对旧表进行了分区,同时保留了原始序列:

CREATE TABLE partitioned_old_style_table_1 (LIKE old_style_table_1 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);
CREATE TABLE partitioned_new_style_table_2 (LIKE new_style_table_2 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);

id 列的 DDL 似乎是 id bigint default nextval('old_style_table_1_id_seq') not nullid bigint default nextval('new_style_table_2_id_seq') not null

到目前为止一切正常。分区表被证明是一个很大的好处,我们决定通过删除旧表来淘汰它们。

DROP TABLE old_style_table_1, new_style_table_2;
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them 
-- Detail: default value for column id of table old_style_table_1 depends on sequence old_style_table_1_id_seq
-- default value for column id of table new_style_table_2 depends on sequence new_style_table_2_id_seq

经过一番思考,我发现序列可能在 postgres 中有所有者,所以我选择更改它们:

ALTER SEQUENCE old_style_table_1_id_seq OWNED BY partitioned_old_style_table_1.id;
DROP TABLE old_style_table_1;
-- Worked out flawlessly

ALTER SEQUENCE new_style_table_2_id_seq OWNED BY partitioned_new_style_table_2.id;
ALTER SEQUENCE new_style_table_2_id_seq OWNED BY NONE;
-- Here's the culprit of the question:
-- [0A000] ERROR: cannot change ownership of identity sequence

因此,很明显,此列将pg_attribute.attidentity 设置为'd' 的事实禁止我:

• 更改列的默认值:

ALTER TABLE new_style_table_2 ALTER COLUMN id SET DEFAULT 0;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column

• 删除默认值:

ALTER TABLE new_style_table_2 ALTER COLUMN id DROP DEFAULT;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column
-- Hint: Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.

• 完全删除标识、列或表(新表已经依赖于序列):

ALTER TABLE new_style_table_2 ALTER COLUMN id DROP IDENTITY IF EXISTS;
-- or
ALTER TABLE new_style_table_2 DROP COLUMN id;
-- or
DROP TABLE new_style_table_2;
-- result in
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them 
-- default value for column id of table partitioned_new_style_table_2 depends on sequence new_style_table_2_id_seq

我查看了documentation,它提供了通往SET IDENTITYADD IDENTITY 的方法,但没有办法将其删除或更改为一次性序列而不尝试删除现有序列。

➥ 那么,我怎样才能从列序列对中删除一个标识标志,这样它就不会影响使用该序列的其他表?

UPD:尝试在本地主机上运行UPDATE pg_attribute SET attidentity='' WHERE attrelid=16816;,仍然收到[2BP01][0A000]。 :/

虽然我设法执行了DROP DEFAULT 值位,但这似乎是一个死胡同。

【问题讨论】:

    标签: postgresql postgresql-10


    【解决方案1】:

    我认为没有一种安全且受支持的方法可以做到这一点(无需修改目录)。幸运的是,序列并没有什么特别之处会导致删除它们成为问题。所以请稍等片刻,然后:

    • 删除使用身份序列的默认值

    • 记录序列的当前值

    • 放下桌子

    • 使用适当的START 值创建一个新序列

    • 使用新序列设置新的默认值

    如果你想要一个标识列,你应该在分区表上定义它,而不是在其中一个分区上。

    【讨论】:

    • 叹息,我认为这是唯一简单的方法,对吧。我试图避免停机,并可能在迁移中创建一个序列,但 START 似乎只接受文字,没有 SELECT nextval('old_sequence') 的东西。我不喜欢手动操作生产数据库的想法,但我也无权访问pg_catalog,所以...好吧,谢谢。 :D
    • 只要稍加努力,停机时间可能只需几秒钟。创建一个起始值比当前序列值高 100000 左右的新序列,逐一更改列默认值,然后删除旧序列。
    • 鉴于我们使用 64 位BIGINT 10^5 增量与其 10^19 范围相比毫无意义,是的。尽管如此,我们的部署实践还是相当严格的,这意味着在我们收集性能数据和记录新错误时,新版本需要在测试轮廓上“休眠”一两天。由于从现在到将迁移应用于生产之间的时间跨度,冒着不一致的 id 风险似乎比停机五分钟更糟糕。至少我是这么认为的,在这个项目上也是如此。 :D 谢谢,我今天会和团队讨论。也许我们会将这些未使用的表截断,直到某个停机时间...
    • 你说的很有道理。我只是想指出,如果停机时间真的很重要,可以避免停机时间。
    猜你喜欢
    • 2018-10-14
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 2023-02-15
    • 2016-03-21
    相关资源
    最近更新 更多