我有一个分区表。它有子项的主键。并且它在父级上有一个匹配的唯一索引,该索引充当分区上主键索引的父级索引。我想将父级上的唯一索引更改为主键约束,而不需要在所有子级上重新创建主键。我尝试的一切都失败了。有办法吗?
重现问题的工作示例:
create table tst (id int,partition_num int) partition by list (partition_num);
create table tst_1 partition of tst for values in (1);
create table tst_2 partition of tst for values in (2);
alter table tst_1 add constraint tst_pk_1 primary key (id,partition_num);
alter table tst_2 add constraint tst_pk_2 primary key (id,partition_num);
create unique index tst_ui1 on tst (id,partition_num);
select relispartition from pg_class where relname = 'tst_pk_1'; -- true
dbname=> \d+ tst
Partitioned table "public.tst"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
---------------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | | | plain | | |
partition_num | integer | | | | plain | | |
Partition key: LIST (partition_num)
Indexes:
"tst_ui1" UNIQUE, btree (id, partition_num)
Partitions: tst_1 FOR VALUES IN (1),
tst_2 FOR VALUES IN (2)
dbname=> \d+ tst_1
Table "public.tst_1"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
---------------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | not null | | plain | | |
partition_num | integer | | not null | | plain | | |
Partition of: tst FOR VALUES IN (1)
Partition constraint: ((partition_num IS NOT NULL) AND (partition_num = 1))
Indexes:
"tst_pk_1" PRIMARY KEY, btree (id, partition_num)
Access method: heap
解决方案看起来很疯狂,但非常简单:
从分区表中分离所有分区
删除分区表上的唯一索引,这不会影响之前分区上的主键
将分区重新附加到分区表
在分区表上创建主键
分离和附加表可以是一个快速操作,因此您可以在很短的停机时间内甚至在单个数据库事务中完成所有这些操作。为了加快速度
ALTER TABLE ... ATTACH PARTITION
,请添加与分区约束完全对应的检查约束,这样如果所有行都与分区约束匹配,PostgreSQL就不必扫描分区。