分表概述

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

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

优势

1. 查询速度大幅提升

2. 删除数据速度更快

3. 可以将使用率低的数据通过表空间技术转移到低成本的存储介质上

场景

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

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

垂直分表

基本过程

1. 创建父表

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

PostgreSQL-优化之分表的更多相关文章

  1. MYSQL性能优化--分库分表

    1.分库分表 1>纵向分表 将本来可以在同一个表的内容,人为划分为多个表.(所谓的本来,是指按照关系型数据库的第三范式要求,是应该在同一个表的.) 分表理由:根据数据的活跃度进行分离,(因为不同 ...

  2. Postgresql分表与优化

    --1.创建主表 CREATE TABLE tbl_partition ( date_key date, hour_key smallint, client_key integer, item_key ...

  3. WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目中有1000万条历史案卷,为某地方坐标系数据,我们的真实 ...

  4. Mysql性能优化三(分表、增量备份、还原)

    接上篇Mysql性能优化二 对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了.如果我拆成100个表,那么每个表只有10万条记录.当然这需要数据在逻 ...

  5. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 大数据支持分表优化

    公司的短信平台,数据量越来越大了,需要对数据进行一些优化,下面是拆分后的数据库量参考. 新开发的软件模块,必须支持分表,拆表的功能一个数据表里,不适合保存1000万以上的记录新开发的业务模块,能分表的 ...

  6. mysql中的优化, 简单的说了一下垂直分表, 水平分表(有几种模运算),读写分离.

    一.mysql中的优化 where语句的优化 1.尽量避免在 where 子句中对字段进行表达式操作select id from uinfo_jifen where jifen/60 > 100 ...

  7. MYSQL性能优化分享(分库分表)

    1.分库分表 很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表mem ...

  8. Sql的分库分表,及优化

    对Sql细节优化 在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考. 首先给大家介绍一下分库分表 分库分表 分库 垂直分库 业务 ...

  9. Mysql MyISAM与InnoDB 表锁行锁以及分库分表优化

    一. 两种存储引擎:MyISAM与InnoDB 区别与作用 1. count运算上的区别: 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需 ...

  10. MySQL优化(一):MySQL分库分表

    一.分库分表种类 1.垂直拆分 在考虑数据拆分的时候,一般情况下,应该先考虑垂直拆分.垂直可以理解为分出来的库表结构是互相独立各不相同的. - 如果有多个业务,每个业务直接关联性不大,那么就可以把每个 ...

随机推荐

  1. Codeforces Round #303 (Div. 2) D. Queue 水题贪心

    题目: 题意:给你n个数值,要求排列这个序列使得第k个数值的前K-1个数的和>=第k个数值的个数尽可能多: #include <iostream> #include <cstd ...

  2. liunx系统中安装lua以及torch

    一直在用pytorch,最近在做项目的时候,遇到了torch的开源代码,所以又开始不得不接触torch以及他所依赖的环境lua. liunx下lua环境的配置代码如下: ''' curl -R -O ...

  3. HDU 5249:KPI(权值线段树)

    KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Desc ...

  4. java命令--jstack 工具【转载】

    一.介绍 jstack是java虚拟机自带的一种堆栈跟踪工具.jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项&qu ...

  5. x-admin

    https://blog.csdn.net/u014793102/article/details/80316335

  6. java实现数据库之间批量插入数据

    package comnf147Package; import java.sql.*; public class DateMigrationLagou { //连接SQLite private Con ...

  7. 20175212童皓桢 《Java程序设计》第11周学习总结

    20175212童皓桢 <Java程序设计>第11周学习总结 教材学习内容总结 一.URL类 1.一个URL对象通常包含最基本的三部分信息:协议.地址.资源 2.构造方法: public ...

  8. LeetCode 14. 最长公共前缀(Longest Common Prefix)

    题目描述 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow ...

  9. spark 笔记 7: DAGScheduler

    在前面的sparkContex和RDD都可以看到,真正的计算工作都是同过调用DAGScheduler的runjob方法来实现的.这是一个很重要的类.在看这个类实现之前,需要对actor模式有一点了解: ...

  10. day3_Python基础三

    参考:http://www.cnblogs.com/jin-xin/articles/7562422.html 一.数据类型 1.1.int:用于计算,不可变,可哈希 数字主要是用于计算用的: #bi ...