分區表特性是PG10新加的一個比較重要的特性,也是衆多PGer翹首以盼的一個功能,相比以前利用「繼承表+約束+觸發器/規則」實現的分區表,PG10分區表在分區管理上和數據寫入上都帶來了很大優點。函數
事實上,PG10的分區特性也是在內置繼承表的基礎上實現的,因此建立的分區實質上也是普通的表結構。目前PG10支持範圍分區和列表分區,哈希分區還不支持(據PG社區人員說,會在PG11加上該功能)。oop
PG10的分區表在建表語法上,主表和分區是單首創建的(區別於Oracle)。下面的列表分區也是同樣。性能
建立主表語法: CREATE TABLE 表名 ( [{ 列名稱 數據_類型} [, ... ] ] ) PARTITION BY RANGE ( [{ 列名稱 } [, ...] ] );
範圍分區的KEY值可由多個字段組成(最多32個字段)。優化
建立分區語法: CREATE TABLE 表名 PARTITION OF 主表 FOR VALUES FROM{ ( 表達式 [, ...] ) | MINVALUE } [, ...] TO { ( 表達式 [, ...] ) | MAXVALUE } [, ...] [ TABLESPACE 表空間名 ]; 參數說明: // FROM ... TO 表示分區的起始值和結束值。 // MINVALUE / MAXVALUE 表示無限小值和無限大值。 // 默認FROM後面的值是包括值分區的約束內,TO後面的值不包括。
示例:spa
highgo=# create table test(n int) partition by range(n); CREATE TABLE highgo=# create table test_1 partition of test for values from (MINVALUE) to (10); CREATE TABLE highgo=# create table test_2 partition of test for values from (10) to (100); CREATE TABLE highgo=# create table test_3 partition of test for values from (100) to (1000); CREATE TABLE highgo=# create table test_4 partition of test for values from (1000) to (10000); CREATE TABLE highgo=# \d+ test 數據表 "public.test" 欄位 | 類型 | Collation | Nullable | Default | 存儲 | 統計目標 | 描述 ------+---------+-----------+----------+---------+-------+----------+------ n | integer | | | | plain | | Partition key: RANGE (n) Partitions: test_1 FOR VALUES FROM (MINVALUE) TO (10), test_2 FOR VALUES FROM (10) TO (100), test_3 FOR VALUES FROM (100) TO (1000), test_4 FOR VALUES FROM (1000) TO (10000) highgo=# \d+ test_2 數據表 "public.test_2" 欄位 | 類型 | Collation | Nullable | Default | 存儲 | 統計目標 | 描述 ------+---------+-----------+----------+---------+-------+----------+------ n | integer | | | | plain | | Partition of: test FOR VALUES FROM (10) TO (100) Partition constraint: ((n IS NOT NULL) AND (n >= 10) AND (n < 100)) highgo=# insert into test select generate_series(0, 9999); INSERT 0 10000 highgo=# explain analyze select * from test; QUERY PLAN --------------------------------------------------------------------------------------------------------- ------ Append (cost=0.00..248.50 rows=17850 width=4) (actual time=0.018..9.374 rows=10000 loops=1) -> Seq Scan on test_1 (cost=0.00..35.50 rows=2550 width=4) (actual time=0.017..0.022 rows=10 loops=1 ) -> Seq Scan on test_2 (cost=0.00..35.50 rows=2550 width=4) (actual time=0.018..0.052 rows=90 loops=1 ) -> Seq Scan on test_3 (cost=0.00..35.50 rows=2550 width=4) (actual time=0.039..0.503 rows=900 loops= 1) -> Seq Scan on test_4 (cost=0.00..142.00 rows=10200 width=4) (actual time=0.040..4.167 rows=9000 loo ps=1) Planning time: 0.525 ms Execution time: 11.881 ms (7 行記錄)
列表的KEY只支持一個字段。code
建立主表語法: CREATE TABLE 表名 ( [{ 列名稱 數據_類型} [, ... ] ] ) PARTITION BY LIST( { 列名稱 } );
建立分區語法: CREATE TABLE 表名 PARTITION OF 主表 FOR VALUES IN ( 表達式 [, ...] ) [ TABLESPACE 表空間名 ];
示例:繼承
highgo=# CREATE TABLE sales (product_id int, saleroom int, province text) PARTITION BY LIST(province); CREATE TABLE highgo=# CREATE TABLE sales_east PARTITION OF sales FOR VALUES IN ('山東','江蘇','上海'); CREATE TABLE highgo=# CREATE TABLE sales_west PARTITION OF sales FOR VALUES IN ('山西','陝西','四川'); CREATE TABLE highgo=# CREATE TABLE sales_north PARTITION OF sales FOR VALUES IN ('北京','河北','遼寧'); CREATE TABLE highgo=# CREATE TABLE sales_south PARTITION OF sales FOR VALUES IN ('廣東','福建'); CREATE TABLE highgo=# \d+ sales 數據表 "public.sales" 欄位 | 類型 | Collation | Nullable | Default | 存儲 | 統計目標 | 描述 ------------+---------+-----------+----------+---------+----------+----------+------ product_id | integer | | | | plain | | saleroom | integer | | | | plain | | province | text | | | | extended | | Partition key: LIST (province) Partitions: sales_east FOR VALUES IN ('山東', '江蘇', '上海'), sales_north FOR VALUES IN ('北京', '河北', '遼寧'), sales_south FOR VALUES IN ('廣東', '福建'), sales_west FOR VALUES IN ('山西', '陝西', '四川') highgo=# \d+ sales_east 數據表 "public.sales_east" 欄位 | 類型 | Collation | Nullable | Default | 存儲 | 統計目標 | 描述 ------------+---------+-----------+----------+---------+----------+----------+------ product_id | integer | | | | plain | | saleroom | integer | | | | plain | | province | text | | | | extended | | Partition of: sales FOR VALUES IN ('山東', '江蘇', '上海') Partition constraint: ((province IS NOT NULL) AND (province = ANY (ARRAY['山東'::text, '江蘇'::text, '上海'::text]))) highgo=# insert into sales values (1001, 2345234, '山東'); INSERT 0 1 highgo=# insert into sales values (1002, 23233, '河北'); INSERT 0 1 highgo=# insert into sales values (1001, 4357233, '廣東'); INSERT 0 1 highgo=# insert into sales values (1002, 67233, '陝西'); INSERT 0 1 highgo=# explain analyze select * from sales; QUERY PLAN --------------------------------------------------------------------------------------------------------- ------- Append (cost=0.00..88.00 rows=4800 width=40) (actual time=0.017..0.038 rows=4 loops=1) -> Seq Scan on sales_east (cost=0.00..22.00 rows=1200 width=40) (actual time=0.016..0.018 rows=1 loo ps=1) -> Seq Scan on sales_west (cost=0.00..22.00 rows=1200 width=40) (actual time=0.004..0.005 rows=1 loo ps=1) -> Seq Scan on sales_north (cost=0.00..22.00 rows=1200 width=40) (actual time=0.004..0.005 rows=1 lo ops=1) -> Seq Scan on sales_south (cost=0.00..22.00 rows=1200 width=40) (actual time=0.005..0.005 rows=1 lo ops=1) Planning time: 0.531 ms Execution time: 0.089 ms (7 行記錄)
a) 系統表get
i. pg_partitioned_table 記錄主表信息的系統表it
ii. 分區的信息記錄在pg_class相關的字段中io
b) 分區函數
i. pg_get_partkeydef (Oid relid) -- 根據主表OID返回分區類型及KEY
highgo=# select pg_get_partkeydef('test'::regclass); pg_get_partkeydef ------------------- RANGE (n) (1 行記錄)
ii. pg_get_partition_constraintdef (Oid relid) -- 根據分區OID獲取分區約束條件
highgo=# select pg_get_partition_constraintdef('test_1'::regclass); pg_get_partition_constraintdef -------------------------------- ((n IS NOT NULL) AND (n < 10)) (1 行記錄)
a) ATTACH操做
ATTACH操做是把和主表有相同表結構的主表變成該主表的一個分區。
範圍分區: ALTER TABLE 主表名 ATTACH PARTITION 表名 FOR VALUES FROM{ ( 表達式 [, ...] ) | MINVALUE } [, ...] TO { ( 表達式 [, ...] ) | MAXVALUE } [, ...]; 列表分區: ALTER TABLE 主表名 ATTACH PARTITION 表名 FOR VALUES IN ( 表達式 [, ...] );
示例:
範圍分區: highgo=# create table test_attach(like test); CREATE TABLE highgo=# alter table test attach partition test_attach for values from (10000) to (MAXVALUE); ALTER TABLE 列表分區: highgo=# CREATE TABLE sales_foreign (like sales) ; CREATE TABLE highgo=# ALTER TABLE sales ATTACH PARTITION sales_foreign FOR VALUES IN('美國','日本'); ALTER TABLE
在對普通表進行ATTACH操做時,若是該普通表中有數據,則表中的數據會進行校驗是否符合約束條件。
b) DETACH 操做
DETACH操做是把主表的分區變成普通表,是ATTACH的反操做。
i.語法 ALTER TABLE 主表名 DETACH PARTITION 分區名;
示例:
範圍分區: highgo=# alter table test detach partition test_attach; ALTER TABLE 列表分區: highgo=# alter table sales detach partition sales_foreign; ALTER TABLE
約束排除(Constraint exclusive)是一種查詢優化技術,在應用在分區特性中,條件查詢中能夠定位到目標分區進行順序掃描,以此來提升分區表檢索性能,這也是使用分區根本意義所在。因此在分區應用在,約束排除的參數constraint_exclusion必定不要設置爲關閉狀態。(系統默認constraint_exclusion的值爲partition,即只對分區表進行約束排除)