淺談PostgreSQL 11 新特性之預設分割槽
文章目錄
PosgtreSQL 11 支援為分割槽表建立一個預設(DEFAULT)的分割槽,用於儲存無法匹配其他任何分割槽的資料。顯然,只有 RANGE 分割槽表和 LIST 分割槽表需要預設分割槽。
CREATE TABLE measurement ( city_id int not null,logdate date not null,peaktemp int,unitsales int ) PARTITION BY RANGE (logdate); CREATE TABLE measurement_y2018 PARTITION OF measurement FOR VALUES FROM ('2018-01-01') TO ('2019-01-01');
以上示例只建立了 2018 年的分割槽,如果插入 2017 年的資料,系統將會無法找到相應的分割槽:
INSERT INTO measurement(city_id,logdate,peaktemp,unitsales) VALUES (1,'2017-10-01',50,200); ERROR: no partition of relation "measurement" found for row DETAIL: Partition key of the failing row contains (logdate) = (2017-10-01).
使用預設分割槽可以解決這類問題。建立預設分割槽時使用 DEFAULT 子句替代 FOR VALUES 子句。
CREATE TABLE measurement_default PARTITION OF measurement DEFAULT; \d+ measurement Table "public.measurement" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description -----------+---------+-----------+----------+---------+---------+--------------+------------- city_id | integer | | not null | | plain | | logdate | date | | not null | | plain | | peaktemp | integer | | | | plain | | unitsales | integer | | | | plain | | Partition key: RANGE (logdate) Partitions: measurement_y2018 FOR VALUES FROM ('2018-01-01') TO ('2019-01-01'),measurement_default DEFAULT
有了預設分割槽之後,未定義分割槽的資料將會插入到預設分割槽中:
INSERT INTO measurement(city_id,200); INSERT 0 1 select * from measurement_default; city_id | logdate | peaktemp | unitsales ---------+------------+----------+----------- 1 | 2017-10-01 | 50 | 200 (1 row)
預設分割槽存在以下限制:
一個分割槽表只能擁有一個 DEFAULT 分割槽;
對於已經儲存在 DEFAULT 分割槽中的資料,不能再建立相應的分割槽;參見下文示例;
如果將已有的表掛載為 DEFAULT 分割槽,將會檢查該表中的所有資料;如果在已有的分割槽中存在相同的資料,將會產生一個錯誤;
雜湊分割槽表不支援 DEFAULT 分割槽,實際上也不需要支援。
使用預設分割槽也可能導致一些不可預見的問題。例如,往 measurement 表中插入一條 2019 年的資料,由於沒有建立相應的分割槽,該記錄同樣會分配到預設分割槽:
INSERT INTO measurement(city_id,'2019-03-25',66,100); INSERT 0 1 select * from measurement_default; city_id | logdate | peaktemp | unitsales ---------+------------+----------+----------- 1 | 2017-10-01 | 50 | 200 1 | 2019-03-25 | 66 | 100 (2 rows)
此時,如果再建立 2019 年的分割槽,操作將會失敗。因為新增新的分割槽需要修改預設分割槽的範圍(不再包含 2019 年的資料),但是預設分割槽中已經存在 2019 年的資料。
CREATE TABLE measurement_y2019 PARTITION OF measurement FOR VALUES FROM ('2019-01-01') TO ('2020-01-01'); ERROR: updated partition constraint for default partition "measurement_default" would be violated by some row
為了解決這個問題,可以先將預設分割槽從分割槽表中解除安裝(DETACH PARTITION),建立新的分割槽,將預設分割槽中的相應的資料移動到新的分割槽,最後重新掛載預設分割槽。
ALTER TABLE measurement DETACH PARTITION measurement_default; CREATE TABLE measurement_y2019 PARTITION OF measurement FOR VALUES FROM ('2019-01-01') TO ('2020-01-01'); INSERT INTO measurement_y2019 SELECT * FROM measurement_default WHERE logdate >= '2019-01-01' AND logdate < '2020-01-01'; INSERT 0 1 DELETE FROM measurement_default WHERE logdate >= '2019-01-01' AND logdate < '2020-01-01'; DELETE 1 ALTER TABLE measurement ATTACH PARTITION measurement_default DEFAULT; CREATE TABLE measurement_y2020 PARTITION OF measurement FOR VALUES FROM ('2020-01-01') TO ('2021-01-01'); \d+ measurement Table "public.measurement" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description -----------+---------+-----------+----------+---------+---------+--------------+------------- city_id | integer | | not null | | plain | | logdate | date | | not null | | plain | | peaktemp | integer | | | | plain | | unitsales | integer | | | | plain | | Partition key: RANGE (logdate) Partitions: measurement_y2018 FOR VALUES FROM ('2018-01-01') TO ('2019-01-01'),measurement_y2019 FOR VALUES FROM ('2019-01-01') TO ('2020-01-01'),measurement_y2020 FOR VALUES FROM ('2020-01-01') TO ('2021-01-01'),measurement_default DEFAULT
官方文件:Table Partitioning
補充:postgresql10以上的自動分割槽分表功能
一.列分表
1.首先建立主分割槽表:
create table fenbiao( id int,year varchar ) partition by list(year)
這裡設定的是根據year列進行資料分表;建立後使用navicat是看不到的;
2.建立分表:
create table fenbiao_2017 partition of fenbiao for values in ('2017')
create table fenbiao_2018 partition of fenbiao for values in ('2018')
這樣這兩天資料會依靠規則插入到不同分表中,如果插入一條不符合規則的資料,則會報錯誤:no partition of relation "fenbiao" found for row.
二.範圍分表
1.以year列為範圍進行分表
create table fenbiao2( id int,year varchar ) partition by range(year)
2.建立分表
create table fenbiao2_2018_2020 partition of fenbiao2 for values from ('2018') to ('2020')
create table fenbiao2_2020_2030 partition of fenbiao2 for values from ('2020') to ('2030')
注意:此時插入year=2020會插入到下面的表;如下面表範圍為2021到2030,則會報錯;同時插入2030也會報錯;範圍相當於時a<=year<b;
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。