ITPub博客

首页 > 数据库 > 数据库开发技术 > postgresql分区表实现方式

postgresql分区表实现方式

原创 数据库开发技术 作者:datapeng 时间:2016-08-10 11:51:42 0 删除 编辑

1. 概述分区表    
分区的意思是把逻辑上的一个大表分割成物理上的几块儿,分区可以提供若干好处:    
1). 某些类型的查询性能可以得到极大提升。    
2). 更新的性能也可以得到提升,因为表的每块的索引要比在整个数据集上的索引要小。如果索引不能全部放在内存里,那么在索引上的读和写都会产生更多的磁盘访问。    
3). 批量删除可以用简单地删除某个分区来实现。    
4). 将很少用的数据可以移动到便宜的、慢一些地存储介质上。     
假设当前的数据库并不支持分区表,而我们的应用所需处理的数据量也非常大,对于这种应用场景,我们不得不人为的将该大表按 照一定的规则,手工拆分成多个小表,让每个小表包含不同区间的数据。这样一来,我们就必须在数据插入、更新、删除和查询之前,先计算本次的指令需要操作的小表。对于有些查询而言,由于查询区间可能会跨越多个小表,这样我们又不得不将多个小表的查询结 果进行 union 操作,以合并来自多个表的数据,并最终形成一个结果集返回给客户端。可见,如果我们正在使用的数据库不支持分区 表,那么在适合其应用的场景下,我们就需要做很多额外的编程工作以弥补这一缺失。然而需要说明的是,尽管功能可以勉强应付, 但是性能却和分区表无法相提并论。    
目前 PostgreSQL 支持的分区形式主要为以下两种:    
1).范围分区: 表被一个或者多个键字字段分区成"范围",在这些范围之间没有重叠的数值分布到不同的分区里。比如,我们可以为特定的商业对象根据数据范围分区,或者根据标识符范围分区。    
2).列表分区: 表是通过明确地列出每个分区里应该出现那些键字值实现的。  

2.测试案例
--登录到数据库
postgres=# select current_database();
 current_database
------------------
 postgres
(1 row)
--创建数据库
postgres=# create database mytest;
--切换数据库
postgres=# \c mytest;
You are now connected to database "mytest" as user "postgres".
--创建父表
mytest=# create table parent(dpart_id bigserial,person_id bigserial,name varchar(20),birth date);
CREATE TABLE
mytest=# select * from parent;
 dpart_id | person_id | name | birth
----------+-----------+------+-------
(0 rows)

--创建子表
pgsql本身像oracle那样的分区定义什么的,通过子表对父表的继承定义实现的,所以有多少个分区,我们就必须建多少个子表。
mytest=# create table child_t01(check(dpart_id > 0 and dpart_id < 20)) inherits(parent);
CREATE TABLE
mytest=# create table child_t02(check(dpart_id >= 20 and dpart_id < 40)) inherits(parent);
CREATE TABLE
mytest=# create table child_t03(check(dpart_id >= 40 and dpart_id < 60)) inherits(parent);
CREATE TABLE
mytest=# create table child_t04(check(dpart_id >= 60 and dpart_id < 80)) inherits(parent);
CREATE TABLE
mytest=# create table child_t05(check(dpart_id >= 80 and dpart_id < 100)) inherits(parent);
CREATE TABLE
mytest=# create table child_t06(check(dpart_id >= 100)) inherits(parent);

--创建规则
建立好子表与父表的继承关系后,不必须定义规则,然后才能把相应的数据插入到指定的子表中,具体过程如下:
mytest=# CREATE OR REPLACE RULE t01_qualified AS
ON INSERT TO parent WHERE dpart_id > 0 and dpart_id < 20
DO INSTEAD
INSERT INTO child_t01 VALUES(NEW.*);
CREATE RULE
其它几个子表也按这种方式创建。

--插入数据测试
mytest=# insert into parent(dpart_id,person_id,name,birth) values(10,10011,'TOM',date'1984-05-04');
INSERT 0 0
mytest=# select * from parent;
 dpart_id | person_id | name |   birth   
----------+-----------+------+------------
       10 |     10011 | TOM  | 1984-05-04
(1 row)

mytest=# select * from only parent;
 dpart_id | person_id | name | birth
----------+-----------+------+-------
(0 rows)
可以看到数据并没有存储到父表中,而存储在子表中

mytest=# select count(1) from parent;
 count
-------
    23
(1 row)

mytest=# select count(*) from only parent;
 count
-------
     0
(1 row)
总共插入了23条,我们可以看到父表中没有数据,都通过子表的。
mytest=#  explain select * from parent where dpart_id = 120;
                           QUERY PLAN                          
----------------------------------------------------------------
 Append  (cost=0.00..1.05 rows=2 width=78)
   ->  Seq Scan on parent  (cost=0.00..0.00 rows=1 width=78)
         Filter: (dpart_id = 120)
   ->  Seq Scan on child_t06  (cost=0.00..1.05 rows=1 width=78)
         Filter: (dpart_id = 120)
从子表中查询出来的。
mytest=# explain select * from parent where dpart_id > 20 and dpart_id <=70;
                           QUERY PLAN                          
----------------------------------------------------------------
 Append  (cost=0.00..3.18 rows=4 width=78)
   ->  Seq Scan on parent  (cost=0.00..0.00 rows=1 width=78)
         Filter: ((dpart_id > 20) AND (dpart_id <= 70))
   ->  Seq Scan on child_t02  (cost=0.00..1.06 rows=1 width=78)
         Filter: ((dpart_id > 20) AND (dpart_id <= 70))
   ->  Seq Scan on child_t03  (cost=0.00..1.06 rows=1 width=78)
         Filter: ((dpart_id > 20) AND (dpart_id <= 70))
   ->  Seq Scan on child_t04  (cost=0.00..1.06 rows=1 width=78)
         Filter: ((dpart_id > 20) AND (dpart_id <= 70))
(9 rows)

3、其它方式
在pgsql中,分区表通过父表与子表的继承关系,再加上定义的规则实现。当然也可以通过其它方式实现,如触发器
首先创建一个函数
CREATE OR REPLACE FUNCTION parent_insert_f()
RETURNS TRIGGER AS
$$
BEGIN
     IF(NEW.dpart_id > 0 and NEW.dpart_id < 20) THEN
         INSERT INTO child_t01 VALUES (NEW.*);
     END IF;
     IF(NEW.dpart_id >= 20 and NEW.dpart_id < 40) THEN
         INSERT INTO child_t02 VALUES (NEW.*);
     END IF;
..............   --以此推算
     RETURN NULL;
END;
$$
LANGUAGE plpgsql ;

通过trigger调用函数
CREATE TRIGGER parent_insert_tr
    BEFORE INSERT ON parent
     FOR EACH row
    EXECUTE PROCEDURE parent_insert_f() ;
   
4、总结
总的说来,分区表实现还是比较麻烦的,不如oracle灵活,如果遇到复杂情况,就比较麻烦了。并且支持的分区也相对少一些。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29371470/viewspace-2123262/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2013-12-06

  • 博文量
    228
  • 访问量
    2684263