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.垂直拆分 在考虑数据拆分的时候,一般情况下,应该先考虑垂直拆分.垂直可以理解为分出来的库表结构是互相独立各不相同的. - 如果有多个业务,每个业务直接关联性不大,那么就可以把每个 ...
随机推荐
- python3基础: 元组tuple、 列表list、 字典dict、集合set。 迭代器、生成器
一.元组: tuple Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组 tup2 = (111, 22, 33, ...
- STCubeMX软件新建Keil和IAR工程使用步骤:
STCubeMX软件新建Keil和IAR工程使用步骤:首先是软件下载(也可在我们的百度云下载):1.STCubeMX下载地址: http://www.stmicroelectronics.co ...
- Unity3D_(游戏)卡牌04_游戏界面
启动屏界面.主菜单界面.选关界面.游戏界面 卡牌01_启动屏界面 传送门 卡牌02_主菜单界面 传送门 卡牌03_选关界面 传送门 卡牌04_游戏界面 传送门 选关界面效果 (源代码在文 ...
- Java常考面试题整理(四)
有关所有Swing相关的面试题,都可以说是凑数的,感觉自己在敲这些的时候感觉一点用处都没有,可以从第72条开始看. 61.说出三种支持重绘(painting)的组件. 参考答案: Canvas,Fra ...
- C++入门经典-例6.18-数组的动态分配,动态获得斐波那契数列
1:有时在获得一定的信息之前,我们并不确定数组的大小.动态分配数组则可以使用变量作为数组的大小,使数组的大小符合我们的要求. 2:科普一下斐波纳契数列:斐波那契数列指的是这样一个数列 1, 1, 2, ...
- js中数组的经典特性
数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长 ...
- Kotlin 的函数定义和使用 (译文 转)
Kotlin 的函数定义和使用 函数声明Kotlin 中的函数使用 fun 关键字声明 fun double(x: Int): Int {}函数用法调用函数使用传统的方法 val result = d ...
- Jquery 选择器的用法
用js 动态生成<ul>标签的<li>条目,因为在动态的创建过程中li的点击事件是不太方便的,因此采用JQuery 的类选择器来实现. html代码: <div id=& ...
- 【转】数组指针&指针数组
转自:https://www.cnblogs.com/mq0036/p/3382732.html 数组指针和指针数组的区别 数组指针(也称行指针)定义 int (*p)[n];()优先级高,首先说明p ...
- 关系代数(Relation Algebra)与SQL语句的对应关系
SQL语句的执行一般是先翻译为关系代数再被执行的(能有效提高执行速度),所以我们有必要 了解关系代数与SQL语句间的对应关系. 就像高中代数由+-*/和数字组成,关系代数是由union.interse ...