PostgreSQL10 新特性(1): 分區表特性

概述

    分區表特性是PG10新加的一個比較重要的特性,也是衆多PGer翹首以盼的一個功能,相比以前利用「繼承表+約束+觸發器/規則」實現的分區表,PG10分區表在分區管理上和數據寫入上都帶來了很大優點。函數

 

特性介紹

    事實上,PG10的分區特性也是在內置繼承表的基礎上實現的,因此建立的分區實質上也是普通的表結構。目前PG10支持範圍分區和列表分區,哈希分區還不支持(據PG社區人員說,會在PG11加上該功能)。oop

1.  範圍分區

        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 行記錄)

2. 列表分區

        列表的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 行記錄)

 

3. 獲取系統信息

    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 行記錄)

 

4. 其餘操做

    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

 

5. 分區的約束排除

    約束排除(Constraint exclusive)是一種查詢優化技術,在應用在分區特性中,條件查詢中能夠定位到目標分區進行順序掃描,以此來提升分區表檢索性能,這也是使用分區根本意義所在。因此在分區應用在,約束排除的參數constraint_exclusion必定不要設置爲關閉狀態。(系統默認constraint_exclusion的值爲partition,即只對分區表進行約束排除)

相關文章
相關標籤/搜索