文章目錄
創建傳統分區表流程
在PostgreSQL10 以前,分區功能比較複雜,需要以下流程:
- 創建父表
- 創建子表
- 給子表添加約束
- 給子表添加索引
- 在父表上定義觸發器
- 啓用constraint_exclusion參數,提高性能。
使用傳統分區表注意事項
- 僅支持範圍分區和列表分區
- 必須是現在父表上創建路由函數和觸發器
- 分區索引、約束需要單獨命令創建,無法一步到位
- 父子表可單獨定義主鍵,因此會存在重複的可能。目前不支持全局主鍵
- update數據時,使數據移動了分區,雖然可以通過觸發器實現,但是會帶來管理成本。
1. 創建父表
假設有一張訂單明細表,需要按照年份進行分區
create table order_detail (id serial ,
order_info varchar(20) ,
order_date timestamp(0) with time zone) ;
2. 創建子表並添加約束
create table order_detail_2015 (check (order_date >= '2015-01-01' and order_date < '2016-01-01') ) inherits(order_detail) ;
create table order_detail_2016 (check (order_date >= '2016-01-01' and order_date < '2017-01-01') ) inherits(order_detail) ;
create table order_detail_2017 (check (order_date >= '2017-01-01' and order_date < '2018-01-01') ) inherits(order_detail) ;
create table order_detail_2018 (check (order_date >= '2018-01-01' and order_date < '2019-01-01') ) inherits(order_detail) ;
create table order_detail_2019 (check (order_date >= '2019-01-01' and order_date < '2020-01-01') ) inherits(order_detail) ;
create table order_detail_2020 (check (order_date >= '2020-01-01' and order_date < '2021-01-01') ) inherits(order_detail) ;
4. 給子表添加索引
create index ind_order_detail_his on order_detail_his using btree (order_date) ;
create index ind_order_detail_2015 on order_detail_2015 using btree (order_date) ;
create index ind_order_detail_2016 on order_detail_2016 using btree (order_date) ;
create index ind_order_detail_2017 on order_detail_2017 using btree (order_date) ;
create index ind_order_detail_2018 on order_detail_2018 using btree (order_date) ;
create index ind_order_detail_2019 on order_detail_2019 using btree (order_date) ;
create index ind_order_detail_2020 on order_detail_2020 using btree (order_date) ;
由於父表不純粹數據,考科一不用再父表上創建索引
5. 在父表上定義觸發器
創建觸發器所使用的的規則函數,設置數據插入父表時的路由規則:
create or replace function fun_order_detail()
returns trigger
as $$
begin
if (new.order_date < '2015-01-01' ) then
insert into order_detail_his values (new.*);
elsif (new.order_date >= '2015-01-01' and new.order_date < '2016-01-01') then
insert into order_detail_2015 values (new.*);
elsif (new.order_date >= '2016-01-01' and new.order_date < '2017-01-01') then
insert into order_detail_2016 values (new.*);
elsif (new.order_date >= '2017-01-01' and new.order_date < '2018-01-01') then
insert into order_detail_2017 values (new.*);
elsif (new.order_date >= '2018-01-01' and new.order_date < '2019-01-01') then
insert into order_detail_2018 values (new.*);
elsif (new.order_date >= '2019-01-01' and new.order_date < '2020-01-01') then
insert into order_detail_2019 values (new.*);
elsif (new.order_date >= '2020-01-01' and new.order_date < '2021-01-01') then
insert into order_detail_2020 values (new.*);
else
raise exception 'order_date out of range. Fix the fun_order_detail() function !! ' ;
end if ;
return null;
end;
$$
LANGUAGE plpgsql;
創建觸發器:
create trigger tri_order_detail
before insert on order_detail for each row execute procedure fun_order_detail();
6. 啓用constraint_exclusion參數
提高性能。
使用分區表
插入數據的時候,只寫父表名字即可:
postgres=# insert into order_detail (id , order_date)
postgres-# values (1, '2015-10-01');
INSERT 0 0
postgres=#
postgres=# insert into order_detail (id , order_date)
postgres-# values (1, '2020-10-01');
INSERT 0 0
postgres=#
postgres=#
postgres=# select * from order_detail;
id | order_info | order_date
----+------------+------------------------
1 | | 2015-10-01 00:00:00+08
1 | | 2020-10-01 00:00:00+08
(2 rows)
那麼數據有沒有按照我們的規則,進入到相應的分區中呢? 我們可以單獨查看子表數據。
postgres=# select * from order_detail_2015;
id | order_info | order_date
----+------------+------------------------
1 | | 2015-10-01 00:00:00+08
(1 row)
postgres=#
postgres=# select * from order_detail_2016;
id | order_info | order_date
----+------------+------------
(0 rows)
postgres=# select * from order_detail_2020;
id | order_info | order_date
----+------------+------------------------
1 | | 2020-10-01 00:00:00+08
(1 row)
管理分區表
添加分區
有兩種方法:
- 方法一 :跟創建分區表的方法一樣
- create table order_detail_2021 … inherits(order_detail);
- create index …
- 更新觸發器
這種方法直接,在創建分區是就將分區繼承到父表了,如果中間步驟有錯誤,可能對生產系統帶來影響。所以推薦方法二。
- 方法二:
1. 創建分區表,但此時僅表結構與父表一樣。兩張表並無關係
create table order_detail_2021 (like order_detail including all);
2. 爲子表添加約束
alter table order_detail_2021 add constraint order_detail_2021_check check (order_date >= '2021-01-01' and order_date < '2022-01-01');
3. 更新觸發器
4. 講子表加入到父表大軍中
alter table order_detail_2021 inherit order_detail;
- 檢查數據
postgres=# insert into order_detail (id , order_date)
postgres-# values (1, '2021-10-01');
INSERT 0 0
postgres=#
postgres=#
postgres=# select * from order_detail_2021;
id | order_info | order_date
----+------------+------------------------
1 | | 2021-10-01 00:00:00+08
(1 row)
postgres=#
postgres=# select * from order_detail;
id | order_info | order_date
----+------------+------------------------
1 | | 2015-10-01 00:00:00+08
1 | | 2020-10-01 00:00:00+08
1 | | 2021-10-01 00:00:00+08
刪除分區
方法1. 刪除子表
postgres=# drop table order_detail_2021;
DROP TABLE
方法2. 去掉繼承關係(推薦)
postgres=# alter table order_detail_2021 no inherit order_detail;
postgres=# \dt+ order*
List of relations
Schema | Name | Type | Owner | Size | Description
--------+-------------------+-------+----------+------------+-------------
public | order_detail | table | postgres | 0 bytes |
public | order_detail_2015 | table | postgres | 8192 bytes |
public | order_detail_2016 | table | postgres | 0 bytes |
public | order_detail_2017 | table | postgres | 0 bytes |
public | order_detail_2018 | table | postgres | 0 bytes |
public | order_detail_2019 | table | postgres | 0 bytes |
public | order_detail_2020 | table | postgres | 8192 bytes |
(7 rows)
分區表相關查詢
查詢分區表使用情況
postgres=# \dt+ order*
List of relations
Schema | Name | Type | Owner | Size | Description
--------+-------------------+-------+----------+------------+-------------
public | order_detail | table | postgres | 0 bytes |
public | order_detail_2015 | table | postgres | 8192 bytes |
public | order_detail_2016 | table | postgres | 0 bytes |
public | order_detail_2017 | table | postgres | 0 bytes |
public | order_detail_2018 | table | postgres | 0 bytes |
public | order_detail_2019 | table | postgres | 0 bytes |
public | order_detail_2020 | table | postgres | 8192 bytes |
(7 rows)