1. 程式人生 > >PostgreSQL之 本地分割槽表的用法和優化

PostgreSQL之 本地分割槽表的用法和優化

資料分割槽的好處
1)分割槽後,單個分割槽表的索引和表都變小了,可以保持在記憶體裡面,適合把熱資料從大表拆分出來的場景。
2)對於大範圍的查詢,大表可以通過索引來避免全表掃描。但是如果分割槽了的話,可以使用分割槽的全表掃描。適合經常要做大範圍掃描的場景,按照範圍分割槽(分割槽後採用全表掃描),減少索引帶來的隨機BLOCK掃描。
3)大批量的資料匯入或刪除,對於大表來說,刪除大量的資料使用DELETE的話會帶來大量的VACUUM操作負擔。而使用分割槽表的話可以直接DROP分割槽,或者脫離子表和父表的繼承關係。
4)使用分割槽表,還有一個好處是,可以把不常用的分割槽放到便宜的儲存上。
5)因為每個表只能放在一個表空間上,表空間和目錄對應,表的大小受到表空間大小的限制,使用分割槽表則更加靈活。

資料庫分割槽表舉例
1)範圍分割槽
根據欄位儲存的值的取值範圍進行分割槽,例如日誌表的時間欄位,使用者表的ID範圍等等。
2)雜湊分割槽
根據欄位儲存值HASH和分割槽數做位元運算得到一個唯一的分割槽ID。(對於版本的升級、軟體的升級一定要確保雜湊演算法的一致)
或者取模也行
例如mod(hashtext(name),16),對16個分割槽的場景

3)list分割槽
與雜湊分割槽類似,但是直接使用欄位值作為分割槽條件。適合KEY值比較少並且比較均勻的場景。
例如按性別欄位作為分割槽欄位,那麼就分成了2個區。

分割槽和表繼承的概念
繼承表自動繼承父表的約束,非空約束。
但是不自動繼承的是(uk,pk,fk,索引,儲存引數等)。

示例:

postgres=# create table p1(id int primary key, info text unique, c1 int check(c1>0), c2 int not null, c3 int unique);
CREATE TABLE                        
postgres=# create table c1(like p1) inherits(p1);                       
NOTICE:  merging column "id" with inherited definition                      
NOTICE:  merging column "info" with inherited definition                        
NOTICE:  merging column "c1" with inherited definition                      
NOTICE:  merging column "c2" with inherited definition                      
NOTICE:  merging column "c3" with inherited definition                      
CREATE
TABLE postgres=# \d+ p1 Table "public.p1" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description ------------+---------+-------------+-----------+----------+-------------+----------------+------------- id | integer | | not null | | plain | | info | text | | | | extended | | c1 | integer | | | | plain | | c2 | integer | | not null | | plain | | c3 | integer | | | | plain | | Indexes: "p1_pkey" PRIMARY KEY, btree (id) "p1_c3_key" UNIQUE CONSTRAINT, btree (c3) "p1_info_key" UNIQUE CONSTRAINT, btree (info) Check constraints: "p1_c1_check" CHECK (c1 > 0) Child tables: c1 子表自動繼承了父表的非空約束,自定義約束。未自動繼承PK和UK。 postgres=# \d+ c1 Table "public.c1" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description -----------+----------+-------------+-----------+----------+------------+----------------+------------- id | integer | | not null | | plain | | info | text | | | | extended | | c1 | integer | | | | plain | | c2 | integer | | not null | | plain | | c3 | integer | | | | plain | | Check constraints: "p1_c1_check" CHECK (c1 > 0) Inherits: p1 如果要繼承UK,PK,索引,儲存結構等,建立時加including all;
postgres=# drop table c1; DROP TABLE postgres=# create table c1(like p1 including all) inherits(p1); NOTICE: merging column "id" with inherited definition NOTICE: merging column "info" with inherited definition NOTICE: merging column "c1" with inherited definition NOTICE: merging column "c2" with inherited definition NOTICE: merging column "c3" with inherited definition NOTICE: merging constraint "p1_c1_check" with inherited definition CREATE TABLE postgres=# \d c1 Table "public.c1" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- id | integer | | not null | info | text | | | c1 | integer | | | c2 | integer | | not null | c3 | integer | | | Indexes: "c1_pkey" PRIMARY KEY, btree (id) "c1_c3_key" UNIQUE CONSTRAINT, btree (c3) "c1_info_key" UNIQUE CONSTRAINT, btree (info) Check constraints: "p1_c1_check" CHECK (c1 > 0) Inherits: p1 可以使用alter table解除和加入繼承關係: postgres=# alter table c1 no inherit p1; ALTER TABLE postgres=# alter table c1 drop constraint p1_c1_check; ALTER TABLE

當主表和繼承表的欄位個數,順序,名字,以及型別或者約束條件有任何不一致時,就無法自動新增繼承。
這裡指的是預設繼承的約束,非空約束等。不包含不會預設繼承的約束UK,PK,FK等。

postgres=# alter table c1 inherit p1;                       
ERROR:  child table is missing constraint "p1_c1_check"                                             
加上約束後就可以了:                      
postgres=# alter table c1 add constraint p1_c1_check check(c1>0);               
ALTER TABLE                     
postgres=# alter table c1 inherit p1;                       
ALTER TABLE 

一個表可以同時繼承多個父表,一個父表可以被多個子表繼承。
但是必須注意,一個表繼承了多個主表的情況,共有欄位上,所有的父表的約束包括not null的定義都必須繼承過來(同樣不包括pk,uk,fk等)。

查主表預設情況下是會連帶查詢所有的子表的,包括更深的子表(子表的子表)。
例如select * from p1;預設會查詢所有子表和自身。

postgres=# explain select * from p1;                        
                         QUERY PLAN                                                 
-------------------------------------------------------------                       
 Append  (cost=0.00..20.70 rows=1071 width=48)                      
   ->  Seq Scan on p1  (cost=0.00..0.00 rows=1 width=48)                        
   ->  Seq Scan on c1  (cost=0.00..20.70 rows=1070 width=48)                        
(3 rows)        

除非使用only或者修改sql_inheritance(預設為on,pg10已經刪除此配置選項,從預設值更改此設定會導致引用父表的查詢不包括子表。然而,SQL標準要求它們被包含在內)。

postgres=# explain select * from only p1;                       
                    QUERY PLAN                                          
---------------------------------------------------                     
 Seq Scan on p1  (cost=0.00..0.00 rows=1 width=48)                      
(1 row)                     

SELECT,UPDATE,DELETE,TRUNCATE,DROP命令在主表上操作預設都會影響到子表。
這些操作必須注意了,小心謹慎。
INSERT和COPY命令,這兩條命令只是對當前表操作的,不會擴充套件到子表。

插入到指定分割槽的實現,使用觸發器(由於insert、copy插入到父表,跟子表沒有關係)

postgres=# create table p(id int, info text, crt_time timestamp);                   
CREATE TABLE                    
postgres=# create table c1(like p) inherits(p);                 
NOTICE:  merging column "id" with inherited definition                  
NOTICE:  merging column "info" with inherited definition                    
NOTICE:  merging column "crt_time" with inherited definition                    
CREATE TABLE                    
postgres=# create table c2(like p) inherits(p);                 
NOTICE:  merging column "id" with inherited definition                  
NOTICE:  merging column "info" with inherited definition                    
NOTICE:  merging column "crt_time" with inherited definition                    
CREATE TABLE                    
postgres=# create table c3(like p) inherits(p);                 
NOTICE:  merging column "id" with inherited definition                  
NOTICE:  merging column "info" with inherited definition                    
NOTICE:  merging column "crt_time" with inherited definition                    
CREATE TABLE    

postgres=# create table c4(like p) inherits(p);                 
NOTICE:  merging column "id" with inherited definition                  
NOTICE:  merging column "info" with inherited definition                    
NOTICE:  merging column "crt_time" with inherited definition                    
CREATE TABLE                    
postgres=# alter table c1 add constraint ck check (crt_time>='2018-04-04' and crt_time<'2018-05-04’);
ALTER TABLE                 
postgres=# alter table c2 add constraint ck check (crt_time>='2018-05-04' and crt_time<'2018-06-04’);
ALTER TABLE                 
postgres=# alter table c3 add constraint ck check (crt_time>='2018-06-04' and crt_time<'2018-07-04’);
ALTER TABLE                 
postgres=# alter table c4 add constraint ck check (crt_time>='2018-07-04' and crt_time<'2018-08-04’);
ALTER TABLE 

postgres=# create or replace function ins_tg() returns trigger as $$				
declare					
begin					
if NEW.crt_time>='2018-04-04'and NEW.crt_time<'2018-05-04' then			
insert into c1(id, info, crt_time) values(NEW.*);					
elseif NEW.crt_time>='2018-05-04' and NEW.crt_time<'2018-06-04' then			
insert into c2(id, info, crt_time) values(NEW.*);					
elseif NEW.crt_time>='2018-06-04' and NEW.crt_time<'2018-07-04' then		
insert into c3(id, info, crt_time) values(NEW.*);					
elseif NEW.crt_time>='2018-07-04' and NEW.crt_time<'2018-08-04' then			
insert into c4(id, info, crt_time) values(NEW.*);					
else					
raise exception 'crt_time overflow.';					
end if;					
return null;					
end;					
$$language plpgsql strict;                 
CREATE FUNCTION

postgres=# create trigger tg1 before insert on p for each row execute procedure ins_tg();   
CREATE TRIGGER                  
postgres=# insert into p(id, info, crt_time) values(1, 'test', now());      
INSERT 0 0                  
postgres=# select * from c1;
 id | info | crt_time 
----+------+----------
(0 rows)
postgres=# select * from c2;
 id | info |          crt_time          
----+------+----------------------------
  1 | test | 2018-05-17 10:48:44.586036
(1 row)
postgres=# select * from c3;
 id | info | crt_time 
----+------+----------
(0 rows)    

postgres=# select * from c4;                    
 id | info | crt_time                   
----+------+----------                  
(0 rows)                                    
postgres=# select * from only p;                    
 id | info | crt_time                   
----+------+----------                  
(0 rows)                                    
postgres=# insert into p(id, info, crt_time) values(1, 'test', '2018-06-04');           
INSERT 0 0                  
postgres=# select * from c2;
 id | info |          crt_time          
----+------+----------------------------
  1 | test | 2018-05-17 10:48:44.586036
(1 row)         

by boluo