PostgreSQL-优化之分表
分表概述
数据库分表,就是把一张表分成多张表,物理上虽然分开了,逻辑上彼此仍有联系。
分表有两种方式:水平分表,即按列分开;垂直分表,即按行分开
优势
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-优化之分表的更多相关文章
- MYSQL性能优化--分库分表
1.分库分表 1>纵向分表 将本来可以在同一个表的内容,人为划分为多个表.(所谓的本来,是指按照关系型数据库的第三范式要求,是应该在同一个表的.) 分表理由:根据数据的活跃度进行分离,(因为不同 ...
- Postgresql分表与优化
--1.创建主表 CREATE TABLE tbl_partition ( date_key date, hour_key smallint, client_key integer, item_key ...
- WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目中有1000万条历史案卷,为某地方坐标系数据,我们的真实 ...
- Mysql性能优化三(分表、增量备份、还原)
接上篇Mysql性能优化二 对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了.如果我拆成100个表,那么每个表只有10万条记录.当然这需要数据在逻 ...
- C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 大数据支持分表优化
公司的短信平台,数据量越来越大了,需要对数据进行一些优化,下面是拆分后的数据库量参考. 新开发的软件模块,必须支持分表,拆表的功能一个数据表里,不适合保存1000万以上的记录新开发的业务模块,能分表的 ...
- mysql中的优化, 简单的说了一下垂直分表, 水平分表(有几种模运算),读写分离.
一.mysql中的优化 where语句的优化 1.尽量避免在 where 子句中对字段进行表达式操作select id from uinfo_jifen where jifen/60 > 100 ...
- MYSQL性能优化分享(分库分表)
1.分库分表 很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表mem ...
- Sql的分库分表,及优化
对Sql细节优化 在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考. 首先给大家介绍一下分库分表 分库分表 分库 垂直分库 业务 ...
- Mysql MyISAM与InnoDB 表锁行锁以及分库分表优化
一. 两种存储引擎:MyISAM与InnoDB 区别与作用 1. count运算上的区别: 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需 ...
- MySQL优化(一):MySQL分库分表
一.分库分表种类 1.垂直拆分 在考虑数据拆分的时候,一般情况下,应该先考虑垂直拆分.垂直可以理解为分出来的库表结构是互相独立各不相同的. - 如果有多个业务,每个业务直接关联性不大,那么就可以把每个 ...
随机推荐
- no matches for kind "ReplicaSet" in version "extensions/v1beta1"
原来的yaml的资源清单为 apiVersion: extensions/v1beta1 kind: ReplicaSet metadata: name: frontend spec: replica ...
- Mongo Cursor
简介 在使用 Java 对数据库进行连接时,都会获取到一个 cursor ,cursor 实际指到的是我们查询数据库的query,而并不是 query 查询到的数据集. 此次在使用 mongo 的 c ...
- python3 使用装饰器,及函数作为参数
#装饰import typesdef shucai(n): print('蔬菜价格7') if type(n)==types.FunctionType: return n()+7 return n+7 ...
- 使用jQuery创建可删除添加行的动态表格,超级简单实用的方法
使用jQuery动态的添加和删除表格里面的行,不多说了直接上代码. <!DOCTYPE html> <html> <head> <meta charset=& ...
- python3笔记十一:python数据类型-List列表
一:学习内容 列表概念 列表创建:创建空列表.创建带有元素的列表 列表访问:取值 列表修改:替换元素.追加元素.追加列表.插入元素 列表删除:移除列表中指定下标处的元素.移除匹配条件的第一个元素.移除 ...
- MYSQL中唯一约束和唯一索引的区别
1.唯一约束和唯一索引,都可以实现列数据的唯一,列值可以有null.2.创建唯一约束,会自动创建一个同名的唯一索引,该索引不能单独删除,删除约束会自动删除索引.唯一约束是通过唯一索引来实现数据的唯一. ...
- MongoDB数据库的基本操作命令
启动服务 net start mongodb 使用 登录本机mongodb Mongodb服务启动之后,打开命令行工具. 登录 mongo 127.0.0.1:27017 27017是mongodb的 ...
- docker—数据卷
启动一个数据容器并挂载本地目录 docker run -itd --name=volume /opt/volume:/tmp/volume --privileged docker.io/nginx-t ...
- spark 笔记 3:Delay Scheduling: A Simple Technique for Achieving Locality and Fairness in Cluster Scheduling
spark论文中说他使用了延迟调度算法,源于这篇论文:http://people.csail.mit.edu/matei/papers/2010/eurosys_delay_scheduling.pd ...
- Android的工程目录主要有哪些
src 源文件gen 生成的文件 R 文件就在此android. jar 依赖的 android sdkassets 资源文件bin 生成的字节码 apk 在此libs 依赖 jar 和 sores ...