从PostgreSQL的列中删除“identity标志”。
从PostgreSQL的列中删除“identity标志”。
我在PostgreSQL 12.9中有一些表,声明方式如下:
-- 这个表是以旧的风格编写的 create table old_style_table_1 ( id bigserial not null primary key, ... ); -- 这个表使用了新的特性 create table new_style_table_2 ( id bigint generated by default as identity, ... );
第二个表似乎是在第10个版本中引入的identity标志进行声明的。
时间过去了,我们对旧表进行了分区处理,同时保留了原始序列:
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 null
和id bigint default nextval('new_style_table_2_id_seq') not null
。
到目前为止一切都运行得很好。分区表证明是一个巨大的好处,我们决定通过删除它们来淘汰旧表。
DROP TABLE old_style_table_1, new_style_table_2; -- [2BP01] ERROR: 不能删除所需的对象,因为其他对象依赖于它们 -- 详细信息: 表old_style_table_1的列id的默认值依赖于序列old_style_table_1_id_seq -- 表new_style_table_2的列id的默认值依赖于序列new_style_table_2_id_seq
经过一番思考,我发现在PostgreSQL中序列可能有所有者,所以我选择改变它们:
ALTER SEQUENCE old_style_table_1_id_seq OWNED BY partitioned_old_style_table_1.id; DROP TABLE old_style_table_1; -- 这一步非常顺利 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; -- 这是问题的罪魁祸首: -- [0A000] ERROR: 无法更改标识序列的所有权
所以,显然这一列的pg_attribute.attidentity设置为'd'
,禁止我:
• 更改列的默认值:
ALTER TABLE new_style_table_2 ALTER COLUMN id SET DEFAULT 0; -- [42601] ERROR: 表"new_style_table_2"的列"id"是标识列
• 删除默认值:
ALTER TABLE new_style_table_2 ALTER COLUMN id DROP DEFAULT; -- [42601] ERROR: 表"new_style_table_2"的列"id"是标识列 -- 提示:使用ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY代替。
• 删除标识、列或整个表(新表已依赖于该序列):
ALTER TABLE new_style_table_2 ALTER COLUMN id DROP IDENTITY IF EXISTS; -- 或者 ALTER TABLE new_style_table_2 DROP COLUMN id; -- 或者 DROP TABLE new_style_table_2; -- 结果是 -- [2BP01] ERROR: 不能删除所需的对象,因为其他对象依赖于它们 -- 表partitioned_new_style_table_2的列id的默认值依赖于序列new_style_table_2_id_seq
我查阅了文档,它提供了SET IDENTITY
或ADD IDENTITY
的方法,但没有办法删除它或将其更改为一个临时序列而不尝试删除现有序列。
➥ 那么,我如何能够从列序列对中移除标识标志,以使其不影响使用此序列的其他表呢?
更新:在本地运行UPDATE pg_attribute SET attidentity='' WHERE attrelid=16816;
,仍然收到[2BP01]
和[0A000]
。:/
虽然我设法执行了DROP DEFAULT
值部分,但似乎是个死胡同。
从上述内容中可以得出,问题的出现原因是想要从PostgreSQL的一个列中移除"identity flag"。解决方法是进行以下步骤:
1. 移除使用identity序列的默认值
2. 记录当前序列的值
3. 删除表
4. 创建一个新的序列,并设置适当的START值
5. 使用新的序列设置新的默认值
同时,文章还提到了如果想要使用identity列,应该在分区表上定义,而不是在其中一个分区上定义。
另外,文章还提到了一种避免停机时间(downtime)的方法,即创建一个新的序列,其起始值比当前序列的值大100000左右,逐个更改列的默认值,然后删除旧的序列。但是,由于部署实践的限制,这种方法可能不适用于该项目。
最后,文章还指出了重要性,如果真的很重要,可以避免停机时间。