PostgreSQL分区表(partitioning)应用实例详解_PostgreSQL

前言

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

1、查询性能大幅提升
2、删除历史数据更快
3、可将不常用的历史数据使用表空间技术转移到低成本的存储介质上
那么什么时候该使用分区表呢?官方给出的指导意见是:当表的大小超过了数据库服务器的物理内存大小则应当使用分区表,接下来结合一个例子具体记录一下创建分区表的详细过程。

创建分区表

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

这个需求就是一个典型的按时间创建分区表,首先看一下步骤:

1.创建父表
2.创建n个子表,每个子表都是继承于父表
3.定义一个规则(Rule)或触发器(Trigger),把对主表的数据插入重定向到合适的分区表

如上所示,整体的大步骤就分为以上三个,当然还可以有一些小的优化措施,比如对于每个分区,在关键字字段上创建一个索引等等。首先来看第一步——创建父表。

在创建分区表之前应当先创建一张“父表”,所有分区表都从它继承,这个表中没有数据,也不要在这个表上定义任何检查约束及索引,现在我们就先创建这样一张表,但之前先建一个序列:

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”:

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月的日志数据:

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张分区表的每个分区键上建立索引:

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数据即可:

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:

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()的统计信息:

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

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
postgresql 分区表、postgresql创建分区表、mysql分区表详解、mbr分区表详解、oracle 分区表详解,以便于您获取更多的相关知识。

时间: 2024-12-09 01:09:10

PostgreSQL分区表(partitioning)应用实例详解_PostgreSQL的相关文章

PostgreSQL教程(十三):数据库管理详解_PostgreSQL

一.概述:     数据库可以被看成是SQL对象(数据库对象)的命名集合,通常而言,每个数据库对象(表.函数等)只属于一个数据库.不过对于部分系统表而言,如pg_database,是属于整个集群的.更准确地说,数据库是模式的集合,而模式包含表.函数等SQL对象.因此完整的对象层次应该是这样的:服务器.数据库.模式.表或其他类型的对象.     在与数据库服务器建立连接时,该连接只能与一个数据库形成关联,不允许在一个会话中进行多个数据库的访问.如以postgres用户登录,该用户可以访问的缺省数据

PostgreSQL教程(四):数据类型详解_PostgreSQL

一.数值类型:     下面是PostgreSQL所支持的数值类型的列表和简单说明: 1. 整数类型:     类型smallint.integer和bigint存储各种范围的全部是数字的数,也就是没有小数部分的数字.试图存储超出范围以外的数值将导致一个错误.常用的类型是integer,因为它提供了在范围.存储空间和性能之间的最佳平衡.一般只有在磁盘空间紧张的时候才使用smallint.而只有在integer的范围不够的时候才使用bigint,因为前者(integer)绝对快得多.     2.

PostgreSQL教程(八):索引详解_PostgreSQL

一.索引的类型:     PostgreSQL提供了多 种索引类型:B-Tree.Hash.GiST和GIN,由于它们使用了不同的算法,因此每种索引类型都有其适合的查询类型,缺省时,CREATE INDEX命令将创建B-Tree索引.         1. B-Tree:   复制代码 代码如下:     CREATE TABLE test1 (         id integer,         content varchar     );     CREATE INDEX test1_i

JavaScript运算符实例详解

核心提示:JavaScript运算符实例详解 根据处理对象的数目: 单元运算符; 二元运算符; 三元运算符. 根据功能: 赋值运算符; = += -= *= /= %=(取余) 算术运算符; + - * / %(取余) ++(递增) --(递减) - 例1: 例2: <Script> var x = y = 3;  with (document) {      write("x = 3, y = 3 <br>");      write("若x = y

精彩实例详解CSS滤镜教程

css|教程|滤镜|详解 使您由浅入深了解CSS滤镜的使用,是一个不错的教程!希望对您学习CSS有用! 1.实例详解CSS滤镜(1)概述 (2005-05-04) 2.实例详解CSS滤镜(2)Mask属性 (2005-05-04) 3.实例详解CSS滤镜(3)Blur属性 (2005-05-04) 4.实例详解CSS滤镜(4)Chroma属性 (2005-05-04) 5.实例详解CSS滤镜(5)DropShadow属性 (2005-05-04) 6.实例详解CSS滤镜(6)Glow属性 (20

实例详解CSS的继承性及其应用

css|继承|详解 所谓CSS的继承是指被包在内部的标签将拥有外部标签的样式性质.继承特性最典型的应用通常发挥在整个网页的样式预设,需要指定为其它样式的部份设定在个别元素里即可.这项特性可以给网页设计者提供更理想的发挥空间.但同时继承也有很多规则,应用的时候容易让人迷惑,donger今天就专门和大家聊聊这方面的应用. 正文 CSS是层叠样式表(Cascading Style Sheets)的简称,它的规范代表了互联网历史上一个独特的发展阶段.现在对于从事网页制作的朋友来说,很少没有听说过CSS了

android 显示gif图片实例详解

  android 显示gif图片实例详解           在android中不支持gif格式的图片,但是由于我希望在我的程序中刚刚加载的时候有一个小人在跑步表示正在加载.而这个小人跑就是一个gif图片.也就是希望程序一启动时就加载gif图片.在网上查找了一些方法不知道是我使用的android的版本高(android4.4)还是什么问题就是加载不出来.最后想了一个办法加载了出来.这个办法就是将gif放在webView中让其显示. 下面是关于这个的代码: activity_prepare_fu

android app进行代码混淆实例详解

  android app进行代码混淆实例详解         接到一个新的任务,对现有项目进行代码混淆.之前对混淆有过一些了解,但是不够详细和完整,知道有些东西混淆起来还是比较棘手的.不过幸好目前的项目不是太复杂(针对混淆这块来说),提前完成--现总结之. 第一部分 介绍下操作流程(eclipse): 1.打开混淆器:找到项目根目录下的project.properties文件,将"#proguard.config=${sdk.dir}/tools/proguard/proguard-andro

Linux 下 Make 命令实例详解

  Linux 下 Make 命令实例详解          Linux 下 make 命令是系统管理员和程序员用的最频繁的命令之一.管理员用它通过命令行来编译和安装很多开源的工具,程序员用它来管理他们大型复杂的项目编译问题.本文我们将用一些实例来讨论 make 命令背后的工作机制. Make 如何工作的 对于不知道背后机理的人来说,make 命令像命令行参数一样接收目标.这些目标通常存放在以 "Makefile" 来命名的特殊文件中,同时文件也包含与目标相对应的操作.更多信息,阅读关