PostgreSQL傳統分區表

創建傳統分區表流程

在PostgreSQL10 以前,分區功能比較複雜,需要以下流程:

  1. 創建父表
  2. 創建子表
  3. 給子表添加約束
  4. 給子表添加索引
  5. 在父表上定義觸發器
  6. 啓用constraint_exclusion參數,提高性能。

使用傳統分區表注意事項

  1. 僅支持範圍分區和列表分區
  2. 必須是現在父表上創建路由函數和觸發器
  3. 分區索引、約束需要單獨命令創建,無法一步到位
  4. 父子表可單獨定義主鍵,因此會存在重複的可能。目前不支持全局主鍵
  5. 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)

管理分區表

添加分區

有兩種方法:

  • 方法一 :跟創建分區表的方法一樣
    1. create table order_detail_2021 … inherits(order_detail);
    2. create index …
    3. 更新觸發器

這種方法直接,在創建分區是就將分區繼承到父表了,如果中間步驟有錯誤,可能對生產系統帶來影響。所以推薦方法二。

  • 方法二:
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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章