通过合理的设计,可以将选择一定的规则,将大表切分多个不重不漏的子表,这就是传说中的partitioning。比如,我们可以按时间切分,每天一张子表,比如我们可以按照某其他字段分割,总之了就是化整为零,提高查询的效能。
怎么实现这个分区表的功能呢?
1 建立大表。
2 创建分区继承
3 定义Rule或者Trigger?
下面根据一个简单的例子,描述这个过程。我们将学生按照低于60分和不低于60分切分成两张子表。
1 建立大表
- CREATE TABLE student (student_id bigserial, name varchar(32), score smallint)
-
CREATE TABLE student_qualified (CHECK (score >= 60 )) INHERITS (student) ;
- CREATE TABLE student_nqualified (CHECK (score < 60)) INHERITS (student) ;
3 定义Rule或者Trigger。
虽然我们定义了CHECK条件,但是往student插入数据时,PostgreSQL并不能根据score是否低于60插入的正确的子表,原因是,你并没有定义这种规则,来告诉数据这么做。我们需要定义Rule或者Trigger,将数据插入到正确的分区表。
先看下Rule的定义:
-
CREATE OR REPLACE RULE insert_student_qualified
-
AS ON INSERT TO student
-
WHERE score >= 60
-
DO INSTEAD
-
INSERT INTO student_qualified VALUES(NEW.*);
-
-
CREATE OR REPLACE RULE insert_student_nqualified
-
AS ON INSERT TO student
-
WHERE score < 60
-
DO INSTEAD
- INSERT INTO student_nqualified VALUES(NEW.*);
我们插入一些记录:
-
INSERT INTO student (name,score) VALUES('Jim',77);
-
INSERT INTO student (name,score) VALUES('Frank',56);
-
INSERT INTO student (name,score) VALUES('Bean',88);
-
INSERT INTO student (name,score) VALUES('John',47);
-
INSERT INTO student (name,score) VALUES('Albert','87');
- INSERT INTO student (name,score) VALUES('Joey','60');
-
SELECT p.relname,c.tableoid,c.*
-
FROM student c, pg_class p
- WHERE c.tableoid = p.oid

我们看到,虽然我们插入的是大表,但是数据却存在了对应的分区子表。符合我们的期望。同时还不影响查询。
Rule是一个分流的办法,还有TRIGGER也能做到让正确的数据流向正确的分区子表。
首先我们定义个function。
-
CREATE OR REPLACE FUNCTION student_insert_trigger()
-
RETURNS TRIGGER AS
-
$$
-
BEGIN
-
IF(NEW.score >= 60) THEN
-
INSERT INTO student_qualified VALUES (NEW.*);
-
ELSE
-
INSERT INTO student_nqualified VALUES (NEW.*);
-
END IF;
-
RETURN NULL;
-
END;
-
$$
- LANGUAGE plpgsql ;
-
CREATE TRIGGER insert_student
-
BEFORE INSERT ON student
-
FOR EACH row
- EXECUTE PROCEDURE student_insert_trigger() ;
-
DROP TABLE STUDENT CASCADE
-
-
CREATE TABLE student (student_id bigserial, name varchar(32), score smallint) ;
-
CREATE TABLE student_qualified (CHECK (score >= 60 )) INHERITS (student) ;
- CREATE TABLE student_nqualified (CHECK (score < 60)) INHERITS (student) ;
为了确认我们的触发器的确触发了,我们打开存储过程的统计开关:
在postgresql.conf中,找到track_functions,改成all
- track_functions = all

执行插入:
-
INSERT INTO student (name,score) VALUES('Jim',77);
-
INSERT INTO student (name,score) VALUES('Frank',56);
-
INSERT INTO student (name,score) VALUES('Bean',88);
-
INSERT INTO student (name,score) VALUES('John',47);
-
INSERT INTO student (name,score) VALUES('Albert','87');
- INSERT INTO student (name,score) VALUES('Joey','60');

我们看到trigger触发了6次。
执行下查询:
-
SELECT p.relname,c.tableoid,c.*
-
FROM student c, pg_class p
- WHERE c.tableoid = p.oid

参考文献
1 PostgreSQL document