随着系统的使用,业务表的数据会变得越来越庞大,当达到一定程度时,会严重影响系统性能,将表分区,可以很好的解决这个问题。分区表的优点包括:
Important:并不是分区就一定能提高性能,如果表本身比较小,分区的话,只会更加消耗性能,根据官方的建议,当单张表的体积大于当前服务器内存的时候,建议分区。
目前pg分区的方法主要有两种,一是利用pg内置的分区组件,二是利用插件pg-partman。pg内置组件只能在才创建表时进行分区,而pg-partman可以将已经有数据的表进行分区,此外,根据网上的一些评测,pg-partman分区后,数据插入的效率更高。网上评测
pg内置有分区的组件,在10.0版本之前,都是通过触发器来进行分区,即插入数据时,根据字段值判断要插入到哪个子表中,效率比较低,而在10.0之后,pg进行了改进,不再需要触发器。pg-11分区方式有RANG、LIST、HASH三种,我们现在使用的是RANGE,所以下面介绍一下pg-11 RANGE方式创建分区表的方法。
-- 主表
CREATE TABLE table_name ( column_name data_type )
PARTITION BY RANGE ( { column_name } [, ... ] )
-- 子表
CREATE TABLE table_name
PARTITION OF parent_table
FOR VALUES
FROM ( { numeric_literal | string_literal | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] )
TO ( { numeric_literal | string_literal | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] )
CREATE TABLE public.country_fence_parent (
id int4 NOT NULL,
branch_range_gis_id int4,
branch_code int4,
branch_name varchar(50) COLLATE pg_catalog.default,
busi_type int4,
cast_type int4,
rgb varchar(10) COLLATE pg_catalog.default,
geom geometry(MULTIPOLYGON, 4326),
fid int4 NOT NULL DEFAULT nextval('country_fence_parent_fid_seq'::regclass)
)PARTITION BY RANGE (busi_type , cast_type);
父表中根据busi_type和cast_type两个字段进行分区;
CREATE TABLE country_fence_child_1_3 PARTITION OF country_fence_parent
FOR VALUES FROM (1,3) TO (1,4);
Tip: 这个地方range的设置,因为是一个范围,所以必须有一个字段的FROM和TO值不能相等,而插入的时候,取值是FROM<=value
CREATE TABLE public.country_fence_child_1_3 (
id int4 NOT NULL,
branch_range_gis_id int4,
branch_code int4,
branch_name varchar(50) COLLATE pg_catalog.default,
busi_type int4,
cast_type int4,
rgb varchar(10) COLLATE pg_catalog.default,
geom geometry(MULTIPOLYGON, 4326),
fid int4 NOT NULL DEFAULT nextval('country_fence_child_1_3_fid_seq'::regclass)
)
ALTER TABLE public.country_fence_parent ATTACH PARTITION public.country_fence_child_1_3
FOR VALUES FROM (1,3) TO (1,4);
即先创建子表,然后把子表挂载到父表上面.
Tip: 子表是对外不可见的,但是可以直接通过sql的方式对其进行增删改查。
insert into country_fence_parent (id, busi_type, cast_type) values (1, 1 , 3);
插入成功,查看sql的执行计划,会发现:
Limit (cost=0.00..18.49 rows=100 width=1294)
-> Append (cost=0.00..636.20 rows=3440 width=1294)
-> Seq Scan on country_fence_child_1_3 (cost=0.00..44.86 rows=229 width=1376)
Filter: (busi_type = 1)
-> Seq Scan on country_fence_child_1_3 (cost=0.00..574.14 rows=3211 width=1289)
Filter: (busi_type = 1)
如果创建子表时,没有定义相应的规则,则会报错,比如:
insert into country_fence_parent (id, busi_type, cast_type) values (1, 3 , 1);
报错:
没有找到关系“country_fence_parent”的分区
待完善,请参考 pg_partman/pg_partman.md at master · pgpartman/pg_partman · GitHub
参考文献:
PostgreSQL: Documentation: 11: 5.10. Table Partitioning GitHub - pgpartman/pg_partman: Partition management extension for PostgreSQL PostgreSQL 10 内置分区 vs pg_pathman_weixin_34380781的博客-CSDN博客 PostgreSQL 11 分区表用法及增强_rocklee的专栏-CSDN博客_postgresql11 分区表