PostgreSQL 11 新特性之跨分區(qū)移動(dòng)數(shù)據(jù)

作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學(xué),十多年數(shù)據(jù)庫(kù)管理與開(kāi)發(fā)經(jīng)驗(yàn),目前在一家全球性的金融公司從事數(shù)據(jù)庫(kù)架構(gòu)設(shè)計(jì)。CSDN學(xué)院簽約講師以及GitChat專欄作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net

文章目錄

在 PostgreSQL 10 中,如果 UPDATE 語(yǔ)句修改了分區(qū)字段的值,導(dǎo)致數(shù)據(jù)需要移動(dòng)到其他分區(qū)時(shí),語(yǔ)句將會(huì)失敗。

-- 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)

   
以下語(yǔ)句更新分區(qū)字段 c1,導(dǎo)致記錄(c1 = 50)需要移動(dòng)到分區(qū) rtable200;不過(guò)語(yǔ)句執(zhí)行失敗。

-- 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 能夠正確處理更新分區(qū)字段的操作:

-- 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)

根據(jù)提交記錄,這種 UPDATE 語(yǔ)句實(shí)際上分為兩步執(zhí)行:從舊的分區(qū)中 DELETE 相應(yīng)記錄,在新的分區(qū)中INSERT 相應(yīng)記錄。對(duì)于并發(fā)場(chǎng)景,這種方式可能會(huì)產(chǎn)生意料之外的行為。官方已經(jīng)記錄該問(wèn)題,并且等待提交補(bǔ)丁。

另外,跨分區(qū)移動(dòng)數(shù)據(jù)的 UPDATE 語(yǔ)句將會(huì)導(dǎo)致觸發(fā)器的執(zhí)行順序更加復(fù)雜,相關(guān)信息可以參考“PostgreSQL 11 新特性之分區(qū)表行級(jí)觸發(fā)器”。

官方文檔:Table Partitioning