PostgreSQL-优化之分表

分表概述

数据库分表,就是把一张表分红多张表,物理上虽然分开了,逻辑上彼此仍有联系。html

分表有两种方式:水平分表,即按列分开;垂直分表,即按行分开sql

优点数据库

1. 查询速度大幅提高服务器

2. 删除数据速度更快函数

3. 能够将使用率低的数据经过表空间技术转移到低成本的存储介质上性能

场景测试

官方建议:当数据表大小超过数据库服务器内存时应该使用分表。spa

 

两种分表方式大体相同,下面以垂直分表为例进行介绍。.net

 

垂直分表

基本过程

1. 建立父表code

2. 建立子表,子表必须继承父表,最好不要新加字段  【加了之后如何,没试过】

  // 能够给每一个子表建立索引

3. 定义一个规则(rule) 或者触发器(trigger),把对父表的写入重定向到对应的分表

 

建立父表

父表无数据,无约束,无索引

CREATE TABLE tbl_partition ( date_key date, hour_key smallint, client_key integer, item_key integer, account integer, expense numeric );

 

建立分表

分表必须继承父表

CREATE TABLE tbl_partition_2016_01() inherits (tbl_partition); CREATE TABLE tbl_partition_2016_02() inherits (tbl_partition); CREATE TABLE tbl_partition_2016_03() inherits (tbl_partition);

 

分表须要添加限制,这些限制决定了每张表容许保存的数据范围,每张表的限制范围不能有重叠。

ALTER TABLE tbl_partition_2016_01 ADD CONSTRAINT tbl_partition_2016_01_check_date_key CHECK (date_Key >= '2016-01-01'::date AND date_Key < '2016-02-01'::date); ALTER TABLE tbl_partition_2016_02 ADD CONSTRAINT tbl_partition_2016_02_check_date_key CHECK (date_Key >= '2016-02-01'::date AND date_Key < '2016-03-01'::date); ALTER TABLE tbl_partition_2016_03 ADD CONSTRAINT tbl_partition_2016_03_check_date_key CHECK (date_Key >= '2016-03-01'::date AND date_Key < '2016-04-01'::date);

 

也能够建表和限制写在一块儿

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 INDEX tbl_partition_date_key_2016_01 ON tbl_partition_2016_01 (date_key,client_key); CREATE INDEX tbl_partition_date_key_2016_02 ON tbl_partition_2016_02 (date_key,client_key); CREATE INDEX tbl_partition_date_key_2016_03 ON tbl_partition_2016_03 (date_key,client_key);

 

建立触发器

表创建完成后,就是写入的工做,如何将数据自动写入对应的分表呢?两种方法,分别是规则(rule)和触发器(trigger),相比 trigger,rule 开销更大,这里使用触发器。

trigger 一般会结合自定义函数来实现分区插入:Function 负责根据条件选择插入,trigger 负责自动调用 Function

 

首先定义 Function

CREATE OR REPLACE FUNCTION tbl_partition_trigger() RETURNS TRIGGER AS $$ BEGIN
  IF NEW.date_key >= DATE '2016-01-01' AND NEW.date_Key < DATE '2016-02-01'
  THEN
    INSERT INTO tbl_partition_2016_01 VALUES (NEW.*); ELSIF NEW.date_key >= DATE '2016-02-01' AND NEW.date_Key < DATE '2016-03-01'
    THEN
      INSERT INTO tbl_partition_2016_02 VALUES (NEW.*); ELSIF NEW.date_key >= DATE '2016-03-01' AND NEW.date_Key < DATE '2016-04-01'
    THEN
      INSERT INTO tbl_partition_2016_03 VALUES (NEW.*); END IF; RETURN NULL; END; $$ LANGUAGE plpgsql;

 

对父表建立触发器

CREATE TRIGGER insert_tbl_partition_trigger BEFORE INSERT ON tbl_partition FOR EACH ROW EXECUTE PROCEDURE tbl_partition_trigger();

 

至此分表成功

 

性能对比

为了对比分表与不分表的性能,我建立了一个全表。

CREATE TABLE tbl_partition_all ( date_key date, hour_key smallint, client_key integer, item_key integer, account integer, expense numeric );

 

把数据先所有写到全表后,迁移到分表

INSERT INTO tbl_partition SELECT * FROM tbl_partition_all;

 

全表9w条数据,分表每一个3w条,测试以下

1. 分表 - 查询单个分表内的数据

EXPLAIN ANALYZE select count(account) ,client_key  from tbl_partition v where v.date_key >='2016-03-02'   and v.date_key <='2016-03-07' group by client_key ;

3月份的数据在一个表内,耗时约 18s 

 

全表查一样的数据

EXPLAIN ANALYZE select count(account) ,client_key  from tbl_partition_all v where v.date_key >='2016-03-02'   and v.date_key <='2016-03-07' group by client_key ;

耗时约 30s

 

2. 分表 - 查询跨分表的数据

EXPLAIN ANALYZE select count(account) ,client_key  from tbl_partition v where v.date_key >='2016-01-02'   and v.date_key <='2016-03-07' group by client_key ;

跨3个表,耗时约 65s

 

全表查一样的数据

EXPLAIN ANALYZE select count(account) ,client_key  from tbl_partition_all v where v.date_key >='2016-01-02'   and v.date_key <='2016-03-07' group by client_key ;

耗时约 87s

 

3. 有同事问为何不直接分呢?不继承单纯按数据建多个表

对此我也进行了测试,单独创建3个表,分别存放以前每一个分表的数据,分别创建索引,而后查询一样的数据

EXPLAIN ANALYZE select count(account) ,client_key  from test1 v where v.date_key >='2016-01-02'   and v.date_key <='2016-01-28' group by client_key union
select count(account) ,client_key  from test2 v where v.date_key >='2016-02-01'   and v.date_key <='2016-02-28' group by client_key union
select count(account) ,client_key  from test3 v where v.date_key >='2016-03-01'   and v.date_key <='2016-03-07' group by client_key ;

耗时约 180s,效率更低

 

总结:分表效率很高,优于全表和多个单表,我这里只是用了少许的数据,性能并无提高很大,若是数据量很大,性能应该提高明显。

 

分表其余操做

删除继承关系

ALTER TABLE tbl_partition_2016_01 NO INHERIT tbl_partition;

 

添加继承关系

ALTER TABLE test1 INHERIT tbl_partition;

 

 

 

参考资料:

https://www.cnblogs.com/winkey4986/p/6824747.html

https://www.jb51.net/article/97937.htm

https://blog.csdn.net/imthemostshuaiin626/article/details/77318911

https://hacpai.com/article/1536655962119

相关文章
相关标签/搜索