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

概述

    分区表特性是PG10新加的一个比较重要的特性,也是众多PGer翘首以盼的一个功能,相比之前利用“继承表+约束+触发器/规则”实现的分区表,PG10分区表在分区管理上和数据写入上都带来了很大优势。

 

特性介绍

    事实上,PG10的分区特性也是在内置继承表的基础上实现的,所以创建的分区实质上也是普通的表结构。目前PG10支持范围分区和列表分区,哈希分区还不支持(据PG社区人员说,会在PG11加上该功能)。

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后面的值不包括。

       示例:

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只支持一个字段。

创建主表语法:
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) 系统表

        i. pg_partitioned_table 记录主表信息的系统表

        

        ii. 分区的信息记录在pg_class相关的字段中

       

    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,即只对分区表进行约束排除)

转载于:https://my.oschina.net/tianbing/blog/1559923

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值