文章目錄
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,logdate,peaktemp,unitsales)
VALUES (1, '2017-10-01', 50, 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,logdate,peaktemp,unitsales)
VALUES (1, '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=yearb;
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- PostgreSQL LIST、RANGE 表分區的實現方案
- PostgreSQL 創建表分區
- 淺析postgresql 數據庫 TimescaleDB 修改分區時間范圍
- 利用python為PostgreSQL的表自動添加分區
- 如何為PostgreSQL的表自動添加分區
- PostgreSQL之分區表(partitioning)
- PostgreSQL分區表(partitioning)應用實例詳解
- PostgreSQL教程(三):表的繼承和分區表詳解
- 淺談PostgreSQL表分區的三種方式