PostgreSQL分区表(partitioning)应用实例

2024-06-02 17:32

本文主要是介绍PostgreSQL分区表(partitioning)应用实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

前言

项目中有需求要垂直分表,即按照时间区间将数据拆分到n个表中,PostgreSQL提供了分区表的功能。分区表实际上是把逻辑上的一个大表分割成物理上的几小块,提供了很多好处,比如:

查询性能大幅提升删除历史数据更快可将不常用的历史数据使用表空间技术转移到低成本的存储介质上

那么什么时候该使用分区表呢?官方给出的指导意见是:当表的大小超过了数据库服务器的物理内存大小则应当使用分区表,接下来结合一个例子具体记录一下创建分区表的详细过程。

创建分区表

首先看一下需求,现在有一张日志表,现在需要按表中的操作时间字段(operation_time)分区,如下图:
这里写图片描述
这里写图片描述

这个需求就是一个典型的按时间创建分区表,首先看一下步骤:<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCrS0vai4uLHttLS9qG649tfTse2jrMO/uPbX07HttrzKx7zMs9DT2ri4se22qNLl0ru49rnm1PKjqFJ1bGWjqbvytKW3osb3o6hUcmlnZ2Vyo6mjrLDRttTW97HttcTK/b7dsuXI69bYtqjP8rW9us/KyrXEt9bH+LHtDQo8cD7I58nPy/nKvqOs1fvM5bXEtPOyvdbovs231s6q0tTJz8j9uPajrLWxyLu7ub/J0tTT0NK70KnQobXE08W7r7TryqmjrLHIyOe21NPaw7+49rfWx/ijrNTaudi8/NfW19a2zsnPtLS9qNK7uPbL99L9tci1yKGjytfPyMC0v7S12tK7sr0mbWRhc2g7Jm1kYXNoO7S0vai4uLHtoaM8L3A+DQo8cD7U2rS0vai31sf4se3Wrsew06a1sc/ItLS9qNK71cUmbGRxdW87uLix7SZyZHF1bzujrMv509C31sf4se22vLTTy/y8zLPQo6zV4rj2se3W0MO709DK/b7do6zSsrK70qrU2tXiuPax7cnPtqjS5cjOus687LLp1LzK+Lywy/fS/aOsz9bU2s7Sw8e+zc/ItLS9qNXi0fnSu9XFse2jrLWr1q7HsM/IvajSu7j20PLB0KO6PC9wPg0KPHByZSBjbGFzcz0="brush:sql;"> CREATE SEQUENCE "public"."t_sys_log_main_id_seq" INCREMENT 1 MINVALUE 1 MAXVALUE 99999999 START 1 CACHE 1; ALTER TABLE "public"."t_sys_log_main_id_seq" OWNER TO "postgres";

接下来创建“父表”,因为是日志表,所以表名命名为“t_sys_log_main”:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

CREATE TABLE "public"."t_sys_log_main" (

"id" int4 DEFAULT nextval('t_sys_log_main_id_seq'::regclass) NOT NULL,

"account_affiliation_code" varchar(100) COLLATE "default" NOT NULL,

"account_affiliation" varchar(50) COLLATE "default" NOT NULL,

"operation_time" timestamp(6) NOT NULL,

"operation_key" varchar(2) COLLATE "default" NOT NULL,

"operation_value" varchar(30) COLLATE "default" NOT NULL,

"operation_loginid" varchar(100) COLLATE "default" NOT NULL,

"operation_message" varchar(300) COLLATE "default" NOT NULL,

"operation_ip" varchar(30) COLLATE "default" NOT NULL

)

WITH (OIDS=FALSE)

 

;

COMMENT ON TABLE "public"."t_sys_log_main" IS '系统日志表';

COMMENT ON COLUMN "public"."t_sys_log_main"."account_affiliation_code" IS '帐号所属机构代码';

COMMENT ON COLUMN "public"."t_sys_log_main"."account_affiliation" IS '帐号所属机构';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_time" IS '操作时间';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_key" IS '操作类型(key)';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_value" IS '操作类型(value)';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_loginid" IS '操作帐号';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_message" IS '操作信息';

COMMENT ON COLUMN "public"."t_sys_log_main"."operation_ip" IS '登录地址';

 

ALTER TABLE "public"."t_sys_log_main" ADD PRIMARY KEY ("id");

运行以上DDL语句创建父表,创建成功后接下来就可以挨个创建分区表了,由于每个分区表都是从父表继承的,所以分区表不会增加任何字段,下面我们按需求创建4张分区子表,分别用于存放9月、10月、11月和12月的日志数据:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

create table t_sys_log_y2016m09

(CHECK (operation_time >= DATE '2016-09-01' AND operation_time< DATE '2016-10-01'))

INHERITS (t_sys_log_main);

 

create table t_sys_log_y2016m10

(CHECK (operation_time >= DATE '2016-10-01' AND operation_time< DATE '2016-11-01'))

INHERITS (t_sys_log_main);

 

create table t_sys_log_y2016m11

(CHECK (operation_time >= DATE '2016-11-01' AND operation_time< DATE '2016-12-01'))

INHERITS (t_sys_log_main);

 

create table t_sys_log_y2016m12

(CHECK (operation_time >= DATE '2016-12-01' AND operation_time< DATE '2017-01-01'))

INHERITS (t_sys_log_main);

如上所示,运行完成后即可创建4张分区子表,在上面的语句中我们添加了一个约束表示只允许插入本月的数据,接下来在这4张分区表的每个分区键上建立索引:

?

1

2

3

4

create index t_sys_log_y2016m09_operation_time ON t_sys_log_y2016m09(operation_time);

create index t_sys_log_y2016m10_operation_time ON t_sys_log_y2016m10(operation_time);

create index t_sys_log_y2016m11_operation_time ON t_sys_log_y2016m11(operation_time);

create index t_sys_log_y2016m12_operation_time ON t_sys_log_y2016m12(operation_time);

到此为止我们的分区表就创建完毕了,接下来需要考虑数据插入的问题,如何才能让不同日期的数据自动的插入与其对应的分区子表中呢?有两种解决方案,分别是:规则(Rule)和触发器(Trigger),相比触发器,Rule的开销更大,所以我在这里就不做过多介绍了,下面直接介绍Trigger的方式。

Trigger通常会结合自定义函数(Function)来实现分区插入,Function负责根据条件选择插入,而Trigger则负责Function的自动调用。首先定义Function,功能很简单,即根据日期区间insert数据即可:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

CREATE

OR REPLACE FUNCTION sys_log_insert_trigger () RETURNS TRIGGER AS $$

BEGIN

 

IF (

    NEW .operation_time >= DATE '2016-09-01'

    AND NEW .operation_time < DATE '2016-10-01'

) THEN

    INSERT INTO t_sys_log_y2016m09

VALUES

    (NEW .*) ;

ELSEIF (

    NEW .operation_time >= DATE '2016-10-01'

    AND NEW .operation_time < DATE '2016-11-01'

) THEN

    INSERT INTO t_sys_log_y2016m10

VALUES

    (NEW .*) ;

ELSEIF (

    NEW .operation_time >= DATE '2016-11-01'

    AND NEW .operation_time < DATE '2016-12-01'

) THEN

    INSERT INTO t_sys_log_y2016m11

VALUES

    (NEW .*) ;

ELSEIF (

    NEW .operation_time >= DATE '2016-12-01'

    AND NEW .operation_time < DATE '2017-01-01'

) THEN

    INSERT INTO t_sys_log_y2016m12

VALUES

    (NEW .*) ;

ELSE

    RAISE EXCEPTION 'Date out of range!' ;

END

IF ; RETURN NULL ;

END ; $$ LANGUAGE plpgsql;

最后再创建触发器用于执行刚才的Function:

?

1

2

3

CREATE TRIGGER sys_log_insert_trigger BEFORE INSERT ON t_sys_log_main

FOR EACH ROW

EXECUTE PROCEDURE sys_log_insert_trigger();

到这里就全部创建完成了,最后测试一下看看结果。为了确认我们的触发器的确触发了,我们打开存储过程的统计开关,在postgresql.conf中,找到track_functions,改成all:
这里写图片描述

接下来就可以运行几条测试insert语句来看看是否能把指定的时间记录分别插入到与其对应的分区子表中,插入之前先看下sys_log_insert_trigger()的统计信息:
这里写图片描述

可以看到目前没有统计记录,接下来插入几条测试数据:

?

1

2

3

4

5

6

7

8

9

10

11

12

INSERT INTO t_sys_log_main VALUES

(1,'200022', '西安高新第一中学初中校区', '2016-9-8 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

INSERT INTO t_sys_log_main VALUES

(1,'200023', '西安高新第一中学初中校区', '2016-9-12 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

INSERT INTO t_sys_log_main VALUES

(1,'200024', '西安高新第一中学初中校区', '2016-10-8 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

INSERT INTO t_sys_log_main VALUES

(1,'200025', '西安高新第一中学初中校区', '2016-11-8 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

INSERT INTO t_sys_log_main VALUES

(1,'200026', '西安高新第一中学初中校区', '2016-12-8 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

INSERT INTO t_sys_log_main VALUES

(1,'200027', '西安高新第一中学初中校区', '2016-12-25 18:49:26.004', '01', 'xx', 'zhsz_t', 'test!', '127.0.0.1');

紧接着再看一下sys_log_insert_trigger()的统计信息:
这里写图片描述

如上图,可以看出调用了6次函数,因为我们插入了6条数据,至此分区表由创建到测试的整个过程就已经成功完成了。

总结

简单记录一下PostgreSQL创建分区表的完整步骤以及注意事项,希望对遇到同样问题的朋友有所帮助,The End。

这篇关于PostgreSQL分区表(partitioning)应用实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1024627

相关文章

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

Nginx内置变量应用场景分析

《Nginx内置变量应用场景分析》Nginx内置变量速查表,涵盖请求URI、客户端信息、服务器信息、文件路径、响应与性能等类别,这篇文章给大家介绍Nginx内置变量应用场景分析,感兴趣的朋友跟随小编一... 目录1. Nginx 内置变量速查表2. 核心变量详解与应用场景3. 实际应用举例4. 注意事项Ng

springboot+mybatis一对多查询+懒加载实例

《springboot+mybatis一对多查询+懒加载实例》文章介绍了如何在SpringBoot和MyBatis中实现一对多查询的懒加载,通过配置MyBatis的`fetchType`属性,可以全局... 目录springboot+myBATis一对多查询+懒加载parent相关代码child 相关代码懒

Java中的随机数生成案例从范围字符串到动态区间应用

《Java中的随机数生成案例从范围字符串到动态区间应用》本文介绍了在Java中生成随机数的多种方法,并通过两个案例解析如何根据业务需求生成特定范围的随机数,本文通过两个实际案例详细介绍如何在java中... 目录Java中的随机数生成:从范围字符串到动态区间应用引言目录1. Java中的随机数生成基础基本随

C++中的解释器模式实例详解

《C++中的解释器模式实例详解》这篇文章总结了C++标准库中的算法分类,还介绍了sort和stable_sort的区别,以及remove和erase的结合使用,结合实例代码给大家介绍的非常详细,感兴趣... 目录1、非修改序列算法1.1 find 和 find_if1.2 count 和 count_if1

MySQL中如何求平均值常见实例(AVG函数详解)

《MySQL中如何求平均值常见实例(AVG函数详解)》MySQLavg()是一个聚合函数,用于返回各种记录中表达式的平均值,:本文主要介绍MySQL中用AVG函数如何求平均值的相关资料,文中通过代... 目录前言一、基本语法二、示例讲解1. 计算全表平均分2. 计算某门课程的平均分(例如:Math)三、结合

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个

PyQt6 键盘事件处理的实现及实例代码

《PyQt6键盘事件处理的实现及实例代码》本文主要介绍了PyQt6键盘事件处理的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起... 目录一、键盘事件处理详解1、核心事件处理器2、事件对象 QKeyEvent3、修饰键处理(1)、修饰键类

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2