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