PostgreSQL 11 新特性之跨分区移动数据

作者: 不剪发的Tony老师
毕业于北京航空航天大学,十多年数据库管理与开发经验,目前在一家全球性的金融公司从事数据库架构设计。CSDN学院签约讲师以及GitChat专栏作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net

文章目录

在 PostgreSQL 10 中,如果 UPDATE 语句修改了分区字段的值,导致数据需要移动到其他分区时,语句将会失败。

-- PostgreSQL 10
CREATE TABLE rtable(c1 INT, c2 VARCHAR(10)) PARTITION BY RANGE(c1);
CREATE TABLE rtable100 PARTITION OF rtable FOR VALUES FROM (1) TO (100);
CREATE TABLE rtable200 PARTITION OF rtable FOR VALUES FROM (101) TO (200);
INSERT INTO rtable(c1, c2) VALUES (50, 'val50');
SELECT * FROM rtable100;
 c1 |  c2   
----+-------
 50 | val50
(1 row)

   
以下语句更新分区字段 c1,导致记录(c1 = 50)需要移动到分区 rtable200;不过语句执行失败。

-- PostgreSQL 10
UPDATE rtable
postgres-# SET c1 = c1 + 100
postgres-# WHERE c1 = 50;
ERROR:  new row for relation "rtable100" violates partition constraint
DETAIL:  Failing row contains (150, val50).

PostgreSQL 11 能够正确处理更新分区字段的操作:

-- PostgreSQL 11
CREATE TABLE rtable(c1 INT, c2 VARCHAR(10)) PARTITION BY RANGE(c1);
CREATE TABLE rtable100 PARTITION OF rtable FOR VALUES FROM (1) TO (100);
CREATE TABLE rtable200 PARTITION OF rtable FOR VALUES FROM (101) TO (200);
INSERT INTO rtable(c1, c2) VALUES (50, 'val50');
SELECT * FROM rtable100;
 c1 |  c2   
----+-------
 50 | val50
(1 row)

UPDATE rtable
   SET c1 = c1 + 100
 WHERE c1 = 50;
SELECT * FROM rtable200;
 c1  |  c2   
-----+-------
 150 | val50
(1 row)

根据提交记录,这种 UPDATE 语句实际上分为两步执行:从旧的分区中 DELETE 相应记录,在新的分区中INSERT 相应记录。对于并发场景,这种方式可能会产生意料之外的行为。官方已经记录该问题,并且等待提交补丁。

另外,跨分区移动数据的 UPDATE 语句将会导致触发器的执行顺序更加复杂,相关信息可以参考“PostgreSQL 11 新特性之分区表行级触发器”。

官方文档:Table Partitioning