PostgreSQL(二十六)分区表管理

目录

一、分区表特点

1、概念:

2、好处:

3、特点:

二、范围分区介绍

1、简介

2、范围分区实验:

三、list分区介绍

1、简介

2、list分区表实验

四、hash分区介绍

1、简介

2、hash分区表实验

五、混合分区介绍

1、简介

2、混合分区表实验

六、总结


一、分区表特点

1、概念:

        分区表的核心是分而治之。将表数据分成更小的物理分片,减少搜索范围,以此可以查询提高性能。

        分区表是关系型数据库中比较常见的对大表的优化方式,数据库管理系统一般都提供了分区管理,而业务可以直接访问分区表而不需要调整业务架构,当然好的性能需要合理的分区访问方式。

2、好处:

(1)改善查询性能

(2)增强可用性:单个小分区表损坏,不影响其他分区表的使用

(3)维护方便

(4)均衡I/O:PG的一个表只能放在一个表空间下,一个表空间只能在一个磁盘上。但是分区表是很多表,可以存储到不同的磁盘上,以达到均衡I/O的目的

3、特点:

(1)pg数据库表分区表的结构

由主表(父表)与分区表(子表)组成

主表是创建子表的模板,它是一个正常的普通表,正常情况下它并不储存任何数据

分区表继承并属于一个主表,分区表中存储所有的数据;

主表与分区表属于一对多的关系,也就是说,一个主表包含多个分区表,而一个分区表只从属于一个主表。

(2)官方声明的分区实现方式

a.继承分区:PG10版本以前都是用的继承分区(后续版本也可使用),但是管理相对麻烦。创建主表、分区表之后,还要创建存储过程、触发器等。继承分区的数据存储是依靠触发器,来把数据分发到不同的分区表内。

b.声明式分区:也叫原生分区,从PG10版本开始支持,相当于"官方支持"的分区表,也是最为推荐的分区方式。虽然与继承分区不一样,但是其内部也是用继承表实现的,只是不需要用户手动干预,使用起来更方便。

声明式分区支持:范围分区,list分区,hash分区

本文章主要介绍这个分区方式。

c.第三方分区管理方式,比如pathman扩展等。

pathman可以让分区表的管理更丝滑。例如:新插入的数据,其值不在分区表范围内时,会插入失败。但是使用pathman,会自动创建一个default分区,将不满足分区范围的数据插入到default分区中,避免插入失败。

二、范围分区介绍

1、简介

范围分区表一般指的一个分区的范围,然后把满足条件的行存放在该分区中。

最常见的是以日期做为分区条件,根据时间段分为不同的分区,存放不同时间段的数据。

2、范围分区实验:

# 创建主表
create table part_range(
order_id int,
name varchar(50)null,
saledate timestamp not null default now())
partition by range(saledate) ;

# 在主表上创建一个主键约束后,子表上就会自动创建一样的主键和索引
alter table part_range add primary key(order_id,saledate);

\d+ part_range

# 创建分区表(子表)
CREATE table p1_202401    //子表名字
PARTITION OF part_range     //基于(继承)哪个主表
FOR values FROM ('2024-01-01 00:00:00') TO ('2024-02-01 00:00:00');    //分区范围

create table p1_202402 partition of part_range for values from ('2024-02-01 00:00:00') to ('2024-01 00:00:00:00');
create table p1_202403 partition of part_range for values from ('2024-03-01 00:00:00') to ('2024-04-01 00:00:00');
create table p1_202404 partition of part_range for values from ('2024-04-01 00:00:00') to ('2024-05-01 00:00:00');
create table p1_202405 partition of part_range for values from ('2024-05-01 00:00:00') to ('2024-06-01 00:00:00');
create table p1_202406 partition of part_range for values from ('2024-06-01 00:00:00') to ('2024-07-01 00:00:00');

# 创建默认分区表,这样有不属于上面分区表的数据插入之后,就会进到默认表中
CREATE TABLE pn_default PARTITION OF part_range DEFAULT;     

# 插入数据
insert into part_range select random()*10000,md5(g::text),g
from generate_series('2024-01-01'::date,'2024-06-30'::date,'1 minute') as g;

# 查看数据
select tableoid::regclass,count(*)
from part_range 
group by tableoid::regclass;

select tableoid::regclass,* from part_range limit 10;

Tip:在某些情况下,需要知道特定行来自哪个表,每个表中都有一个名为tableoid的系统列,使用regclass别名类型,它将象征性地打印表oid,可以列出行的原始表。

# 通过主表访问分区表(强烈建议条件列是分区列,否则分区表无意义,数据库会把所有分区表都遍历一遍,大大降低性能)

explain select * from part_range where saledate='2024-05-02';

# 通过子表访问(通过子表访问时,如果访问列不是分区列,但是索引列,也可以使用索引来提高一部分性能)
explain select * from p1_202401 where order_id=100;
explain select from p1_202401 where order_id=100;

三、list分区介绍

1、简介

        list分区以指定的分区值将数据存放到对应的分区上,然后把满足条件的行存放在该分区中,最常见的是以某列值为分区条件,根据不同的列值存放在不同的分区。

2、list分区表实验

# 创建主表
create table part_list(
city_id int not null,
name varchar(30),
population int)
partition by list(name) ;

create index part_list_idx on part_list (name);    //list:分区方式;name:分区列


\d+ part_list

# 创建分区表
create table p1_list partition of part_list for values in ('fujian','zhejiang');
create table p2_list partition of part_list for values in ('shandong','jiangxi');

# 插入数据
insert into part_list(city_id,name,population) values(1,'fujian',10);
insert into part_list(city_id,name,population) values(2,'zhejiang',20);
insert into part_list(city_id,name,population) values(3,'shandong',10);
insert into part_list(city_id,name,population) values(4,'jiangxi',30);

# 查看数据
select tableoid::regclass,* from part_list;

# 查看执行计划
explain select * from part_list where name='fujian';

四、hash分区介绍

1、简介

        hash分区将数据散列存储在各个分区上,以打散热点数据存放到对应的分区上,然后把满足条件的行存放在该分区中,最常见的是平均的把数据放在不同的分区。

2、hash分区表实验

# 创建主表
create table part_hash
(order_id int,
name varchar(10))
partition by hash (order_id);

create index part_hash_idx on part_hash (order_id);

\d+ part_hash

# 创建子表
create table p1_hash partition of part_hash for values with (modulus 3,remainder 0 );   //modules:除数;remainder:取模(余数)

create table p2_hash partition of part_hash for values with (modulus 3,remainder 1);
create table p3_hash partition of part_hash for values with (modulus 3,remainder 2);

# 插入数据
insert into part_hash values(generate_series(1,10000),'a');

# 查询数据
select tableoid::regclass,count(1) from part_hash group by tableoid::regclass;

# 查看执行计划
explain select * from part_hash where order_id=1000;

五、混合分区介绍

1、简介

        PG分区下面也可以建立子分区构成联级模式,子分区可以有不同的分区方式,这样的分区成为混合分区。

        即:主表 --> 子表(分区表)--> 子分区  的联级关系。

        当分区表的数据倾斜比较大时,就可以通过给大数据分区表创建子分区的方式平衡倾斜。

        子分区的分区列可以和分区表的分区列一样,也可以不一样,在主表中指定子表的分区列,在子表中指定子分区的分区列。

        例如下面这个例子,分区表以sale_date分区,子分区以category:

2、混合分区表实验

1、创建主表
create table part_hunhe(
id int not null,
name varchar(20),
saledate timestamp)
partition by range(saledate) ;    //在主表指定,分区表使用哪一列进行分区。同样的,应该在分区表指定,子分区表使用哪一列进行分区。


\d+ part_hunhe

# 创建分区表
create table part_2001 partition of part_hunhe for values from ('2023-01-01 00:00:00') to ('2023-02-01 00:00:00')
partition by list(name);     //在分区表创建时,指定子分区使用什么列进行分区

create table part_2002 partition of part_hunhe for values from('2023-02-01 00:00:00') to ('2023-03-01 00:00:00')
partition by list(name);

create table part_2003 partition of part_hunhe for values from('2023-03-01 00:00:00') to ('2023-04-01 00:00:00')
partition by list(name);

create table part_2004 partition of part_hunhe for values from('2023-04-01 00:00:00') to ('2023-05-01 00:00:00')
partition by list(saledate);

create table part_2005 partition of part_hunhe for values from('2023-05-01 00:00:00') to ('2023-06-01 00:00:00')
partition by range(saledate);

\d+ part_2001


# 创建子分区表
create table part_3001 partition of part_2001 for values in ('abc');
create table part_3002 partition of part_2001 for values in ('def');
create table part_3003 partition of part_2001 for values in ('jkl');
create table part_3004 partition of part_2004 for values in ('2023-04-01 00:00:00');
create table part_3005 partition of part_2005 for values from ('2023-05-01 00:00:00') to ('2023-05-10 00:00:00');

\d+ part_3001

# 插入数据
insert into part_hunhe values(random()*10000,'abc','2023-01-01 08:00:00');
insert into part_hunhe values(random()*10000,'def','2023-01-01 08:00:00');

# 查询数据
select tableoid::regclass,* from part_hunhe;

# 查看执行计划
explain select * from part_hunhe where name='adc';

 

六、总结

1、pg不支持interval分区,没有自带的自动新增分区功能

2、分区表的分区本身也是表,主表不存储数据,分区表存储数据

3、truncate、vacuum、analyze主表会执行所有分区。truncateonly不能在主表上执行,但可以在存数据的分区表上执行,仅清除这个分区表

4、range、hash分区的分区键可以有多个列,list分区键只能是单个列或表达式

5、default分区表会接收不在声明的范围中的数据;如果没有default分区,插入范围外的数据会直接报错

//创建default子表:CREATE TABLE tbl_name_default PARTITION OF tbl_log DEFAULT;

6、如果要新增分区,需要注意default分区中是否有这个新增分区的数据,如果有,则会发生冲突导致报错(不会自动迁移过去)。

7、partition of创建的分区会自动创建主表上定义的索引、约束、行级触发器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值