PostgreSQL 9.x, 10, 11 hash分区表 用法举例

标签

PostgreSQL , 分区表 , 优化器 , 分区过滤 , hash 分区


背景

PostgreSQL 10开始内置分区表语法,当时只支持了range,list两种分区,实际上可以通过LIST实现HASH分区。

PostgreSQL 10 hash 分区表

使用list支持hash分区

postgres=# create table p (id int , info text, crt_time timestamp) partition by list (abs(mod(id,4)));  
CREATE TABLE  
  
postgres=# create table p0 partition of p for values in (0);  
CREATE TABLE  
postgres=# create table p1 partition of p for values in (1);  
CREATE TABLE  
postgres=# create table p2 partition of p for values in (2);  
CREATE TABLE  
postgres=# create table p3 partition of p for values in (3);  
CREATE TABLE  

分区表如下

postgres=# \d+ p  
                                                Table "public.p"  
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description   
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------  
 id       | integer                     |           |          |         | plain    |              |   
 info     | text                        |           |          |         | extended |              |   
 crt_time | timestamp without time zone |           |          |         | plain    |              |   
Partition key: LIST (abs(mod(id, 4)))  
Partitions: p0 FOR VALUES IN (0),  
            p1 FOR VALUES IN (1),  
            p2 FOR VALUES IN (2),  
            p3 FOR VALUES IN (3)  

写入数据

postgres=# insert into p select generate_series(1,1000),md5(random()::text),now();  
INSERT 0 1000  
postgres=# select tableoid::regclass,id from p limit 10;  
 tableoid | id   
----------+----  
 p0       |  4  
 p0       |  8  
 p0       | 12  
 p0       | 16  
 p0       | 20  
 p0       | 24  
 p0       | 28  
 p0       | 32  
 p0       | 36  
 p0       | 40  
(10 rows)  

普通的查询,无法做到分区的过滤

postgres=# explain select * from p where id=1 ;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..96.50 rows=24 width=44)  
   ->  Seq Scan on p0  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 1)  
   ->  Seq Scan on p1  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 1)  
   ->  Seq Scan on p2  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 1)  
   ->  Seq Scan on p3  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 1)  
(9 rows)  

一定要带上分区条件,才可以做到分区过滤

postgres=# explain select * from p where id=1 and abs(mod(id, 4))=abs(mod(1, 4));  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..32.60 rows=1 width=44)  
   ->  Seq Scan on p1  (cost=0.00..32.60 rows=1 width=44)  
         Filter: ((id = 1) AND (abs(mod(id, 4)) = 1))  
(3 rows)  

PostgreSQL 11 hash 分区表

PostgreSQL 11同样可以使用与10一样的方法,LIST来实现HASH分区,但是有一个更加优雅的方法,直接使用HASH分区。

postgres=# create table p (id int , info text, crt_time timestamp) partition by hash (id);  
CREATE TABLE  
  
postgres=# create table p0 partition of p  for values WITH (MODULUS 4, REMAINDER 0);  
CREATE TABLE  
postgres=# create table p1 partition of p  for values WITH (MODULUS 4, REMAINDER 1);  
CREATE TABLE  
postgres=# create table p2 partition of p  for values WITH (MODULUS 4, REMAINDER 2);  
CREATE TABLE  
postgres=# create table p3 partition of p  for values WITH (MODULUS 4, REMAINDER 3);  
CREATE TABLE  

表结构如下

postgres=# \d+ p  
                                                Table "public.p"  
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description   
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------  
 id       | integer                     |           |          |         | plain    |              |   
 info     | text                        |           |          |         | extended |              |   
 crt_time | timestamp without time zone |           |          |         | plain    |              |   
Partition key: HASH (id)  
Partitions: p0 FOR VALUES WITH (modulus 4, remainder 0),  
            p1 FOR VALUES WITH (modulus 4, remainder 1),  
            p2 FOR VALUES WITH (modulus 4, remainder 2),  
            p3 FOR VALUES WITH (modulus 4, remainder 3)  

表分区定义,内置的约束是一个HASH函数的返回值

postgres=# \d+ p0  
                                                Table "public.p0"  
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description   
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------  
 id       | integer                     |           |          |         | plain    |              |   
 info     | text                        |           |          |         | extended |              |   
 crt_time | timestamp without time zone |           |          |         | plain    |              |   
Partition of: p FOR VALUES WITH (modulus 4, remainder 0)  
Partition constraint: satisfies_hash_partition('180289'::oid, 4, 0, id)  
  
  
postgres=# \d+ p1  
                                                Table "public.p1"  
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description   
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------  
 id       | integer                     |           |          |         | plain    |              |   
 info     | text                        |           |          |         | extended |              |   
 crt_time | timestamp without time zone |           |          |         | plain    |              |   
Partition of: p FOR VALUES WITH (modulus 4, remainder 1)  
Partition constraint: satisfies_hash_partition('180289'::oid, 4, 1, id)  

这个hash函数的定义如下,他一定是一个immutable 函数,所以可以用于分区过滤

postgres=# \x  
Expanded display is on.  
postgres=# \df+ satisfies_hash_partition  
List of functions  
-[ RECORD 1 ]-------+--------------------------------------  
Schema              | pg_catalog  
Name                | satisfies_hash_partition  
Result data type    | boolean  
Argument data types | oid, integer, integer, VARIADIC "any"  
Type                | func  
Volatility          | immutable  
Parallel            | safe  
Owner               | postgres  
Security            | invoker  
Access privileges   |   
Language            | internal  
Source code         | satisfies_hash_partition  
Description         | hash partition CHECK constraint  

PostgreSQL 11终于可以只输入分区字段值就可以做到分区过滤了

postgres=# explain select * from p where id=1;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..24.16 rows=6 width=44)  
   ->  Seq Scan on p0  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 1)  
(3 rows)  
  
postgres=# explain select * from p where id=0;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..24.16 rows=6 width=44)  
   ->  Seq Scan on p0  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 0)  
(3 rows)  
  
postgres=# explain select * from p where id=2;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..24.16 rows=6 width=44)  
   ->  Seq Scan on p2  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 2)  
(3 rows)  
  
postgres=# explain select * from p where id=3;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..24.16 rows=6 width=44)  
   ->  Seq Scan on p1  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 3)  
(3 rows)  

它受控于一个开关,当关闭后,就无法只通过分区值来过滤分区。

postgres=# set enable_partition_pruning =off;  
SET  
postgres=# explain select * from p where id=0;  
                        QUERY PLAN                          
----------------------------------------------------------  
 Append  (cost=0.00..96.62 rows=24 width=44)  
   ->  Seq Scan on p0  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 0)  
   ->  Seq Scan on p1  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 0)  
   ->  Seq Scan on p2  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 0)  
   ->  Seq Scan on p3  (cost=0.00..24.12 rows=6 width=44)  
         Filter: (id = 0)  
(9 rows)  

PostgreSQL 继承表 hash 分区表实现

《PostgreSQL 传统 hash 分区方法和性能》

postgres=# explain select * from tbl where abs(mod(id,4)) = abs(mod(1,4)) and id=1;    
                                QUERY PLAN                                    
--------------------------------------------------------------------------    
 Append  (cost=0.00..979127.84 rows=3 width=45)    
   ->  Seq Scan on tbl  (cost=0.00..840377.67 rows=2 width=45)    
         Filter: ((id = 1) AND (abs(mod(id, 4)) = 1))    
   ->  Seq Scan on tbl1  (cost=0.00..138750.17 rows=1 width=45)    
         Filter: ((id = 1) AND (abs(mod(id, 4)) = 1))    
(5 rows)    

pg_pathman分区方法

支持9.5以上的版本

《PostgreSQL 9.5+ 高效分区表实现 - pg_pathman》

小结

1、PostgreSQL 10内置分区表,为了HASH分区,可以使用LIST分区的方法,但是为了让数据库可以自动过滤分区,一定要带上HASH分区条件表达式到SQL中。

2、PostgreSQL 11内置分区表,内置了HASH分区,并且支持只按照HASH分区条件,自动过滤分区。

3、继承表的方法,同样可以实现HASH分区,需要创建触发器,同时主表在查询时依旧会被查询到。

以上三种方法,必须保证constraint_exclusion参数设置为partition或者on, 否则无法做到分区自动过滤。

对于PostgreSQL 11,为了实现只输入分区字段的值就能够满足分区自动过滤,还需要设置enable_partition_pruning为on.

索性这些参数默认都是OK的。

4、pg_pathman是通过custom scan接口实现的分区,是目前为止,性能最好的,锁粒度最低的方法。

参考

《PostgreSQL 11 preview - 分区表 增强 汇总》

《PostgreSQL 自动创建分区实践 - 写入触发器》

《PostgreSQL 11 preview - 分区过滤控制参数 - enable_partition_pruning》

《Greenplum 计算能力估算 - 暨多大表需要分区,单个分区多大适宜》

《PostgreSQL 11 preview - 分区表智能并行聚合、分组计算(已类似MPP架构,性能暴增)》

《PostgreSQL 并行vacuum patch - 暨为什么需要并行vacuum或分区表》

《分区表锁粒度差异 - pg_pathman VS native partition table》

《PostgreSQL 11 preview - 分区表用法及增强 - 增加HASH分区支持 (hash, range, list)》

《PostgreSQL 11 preview - Parallel Append(包括 union all\分区查询) (多表并行计算) sharding架构并行计算核心功能之一》

《PostgreSQL 11 preview - 分区表智能并行JOIN (已类似MPP架构,性能暴增)》

《PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程)》

《PostgreSQL 商用版本EPAS(阿里云ppas(Oracle 兼容版)) - 分区表性能优化 (堪比pg_pathman)》

《PostgreSQL 传统 hash 分区方法和性能》

《HTAP数据库 PostgreSQL 场景与性能测试之 45 - (OLTP) 数据量与性能的线性关系(10亿+无衰减), 暨单表多大需要分区》

《PostgreSQL 10 内置分区 vs pg_pathman perf profiling》

《PostgreSQL 10.0 preview 功能增强 - 内置分区表》

《PostgreSQL 9.5+ 高效分区表实现 - pg_pathman》

PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程) 摘要: 标签 PostgreSQL , 分区表 , bind , spin lock , 性能分析 , sleep 进程 , CPU空转 , cache 背景 实际上我写过很多文档,关于分区表的优化: 《PostgreSQL 商用版本EPAS(阿里云ppas) - 分区表性能优化 (堪比pg_pathman)》 《PostgreSQL 传统 hash 分区方法和性能》 《PostgreSQL 10 阅读详情

相关推荐

Rocky Linux 9 下用 dnf 安装 PostgreSQL 15 实战指南

PostgreSQL 是企业级开源关系型数据库的代表,其稳定性和标准兼容性在 Linux 服务器部署中尤为关键。在 Rocky Linux 9 这一 CentOS 替代发行版上,采用系统原生 dnf 包管理器安装 PostgreSQL 15,可确保 SELinux 策略适配、日志体系集成与二进制兼容性,避免 Docker 容器或手动 RPM/源码编译带来的监控断裂、权限冲突与升级风险。该方案依托 appstream 模块流机制实现版本可控,通过 initdb 初始化、postgresql.conf 调优和

weixin_34416649的博客 542

simhash原理以及用python3实现simhash算法详解(附python3源码)

Simhash应用场景:计算大规模文本相似度,实现海量文本信息去重。 Simhash算法原理:通过hash值比较相似度,通过两个字符串计算出的hash值,进行异或操作,然后得到相差的个数,数字越大则差异越大。

数据知道的博客 2万+

Ubuntu 12.04下PostgreSQL 9.1主从复制实战指南

PostgreSQL主从复制是保障数据库高可用与读写分离的核心机制,其底层依赖WAL日志流式同步与物理复制原理,具备事务强一致、低延迟、零应用侵入等技术价值。在资源受限或系统固化场景中,如老旧ERP、工业控制中间件所依赖的Ubuntu 12.04(Linux 3.2内核+OpenSSL 1.0.1)环境,必须采用兼容PostgreSQL 9.1的物理复制方案,而非现代逻辑复制;该方案通过streaming replication实现毫秒级同步,并借助hot_standby开启从库只读服务能力,从而支撑报表查

dbp5156的博客 421

PostgreSQLPostgreSQL两层hash分区表(适用于大数据量表)

【代码】【PostgreSQLPostgreSQL两层hash分区表

tttzzzqqq2018的博客 1354

PostgreSQL 12: 新增 pg_partition_tree() 函数显示分区表信息

对于一维分区表PostgreSQL 提供的元命令足够查看分区的完整信息,但对于多维分区表,元命令无法查看详尽的分区信息,PostgreSQL 12 提供的分区函数很容易做到这点。尽管二维分区表的使用并不是很多,分区表函数提供了分区表查询的另一种途径。

snowyar的专栏 1576

Postgresql 10 HASH分区实现

前面简单介绍了postgres10分区相关情况,里面谈到基于postgres10这套分区实现hash分区比较麻烦,但仔细考虑后发现其实也是可以实现的,下面介绍在原有range/list基础上比较粗糙的hash分区的实现 。 注意:本文中思路及后附代码是研究学习用,由于本人水平限制,难免会有遗漏及错误的地方,不保证正确性,并且是个人见解,希望能抛砖引玉。

postgres20的博客 7663

PostgreSQL 传统 hash 分区方法和性能

背景 除了传统的基于trigger和rule的分区,PostgreSQL 10开始已经内置了分区功能(目前仅支持list和range),使用pg_pathman则支持hash分区。 从性能角度,目前最好的还是pg_pathman分区。 但是,传统的分区手段,依旧是最灵活的,在其他方法都不奏效时,可以考虑传统方法。 如何创建传统的hash分区 1、创建父表 creat

技术学习与分享 1495

9.x - 13.0 postgresql 分区表新特性及简单用法

一、 分区表定义与意义 1. 分区表的定义 把一个大的物理表分成若干个小物理表,并使得这些小物理表在逻辑上可以被当成一张表来使用。 主表/父表/Master Table 主表是创建子表的模板,是一个正常的普通表,一般主表并不存任何数据。 子表/分区表/Chlid Table/Partition Table 子表继承并属于一个主表,与主表是一对多的关系,子表中存储所有的数据 2....

Hehuyi_In的博客 5575

postgresql分区表

postgresql分区表

归来仍少年 4709

pgstgresql 分区表

pgsql 创建分区表

weixin_46061449的博客 1659

PostgreSQL 各个版本之间重要变化

到这里,对与 PostgreSQL 相信你已经有了大致合适的版本选择。

顺其自然~专栏 1160

PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程)...

摘要: 标签 PostgreSQL , 分区表 , bind , spin lock , 性能分析 , sleep 进程 , CPU空转 , cache 背景 实际上我写过很多文档,关于分区表的优化: 《PostgreSQL 商用版本EPAS(阿里云ppas) - 分区表性能优化 (堪比pg_pathman)》 《PostgreSQL 传统 hash 分区方法和性能》 《PostgreSQL 10...

maoreyou的博客 2961

PostgreSQL 通过隐蔽时间信道泄露 MD5 哈希密码HGVE-2026-E012

PostgreSQL 认证中 MD5 哈希密码比较存在隐蔽时间信道,允许攻击者恢复足以完成认证的用户凭据。同时建议迁移存量 MD5 密码至 scram-sha-256,调整 pg_hba.conf 禁用 md5 认证,并要求用户重置历史 MD5 口令。链接: https://pan.baidu.com/s/1wbOp7Qhb8-pepw7ko63zag?pwd=b56y 提取码: b56y。链接: https://pan.baidu.com/s/15nI0Vgxmy5Yy-hCspSOm2g?

HighGO 204

第6讲 PostgreSQL 表分区

对于需要定期进行数据归档的表,使用 PostgreSQL 提供的 DETACH 方式,直接解除与父表的继承关系,而无需在原表上进行备份后删除,既能极大的提高工作效率,也能减少对表不必要的操作,从而可降低表的膨胀,同时也以减少 WAL 的量,从而节省不必要资源消耗。PG 表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。为了解决这个问题,可以先将默认分区从分区表中卸载(DETACH PARTITION),创建新的分区,将默认分区中的相应的数据移动到新的分区,最后重新挂载默认分区。

zxcdxy123的博客 778

Ubuntu 16.04 安装 PostgreSQL 9.5 实战指南:apt 原理与安全连接配置

PostgreSQL 是一款功能完备的开源关系型数据库,其部署依赖操作系统底层包管理机制。在 Ubuntu 系统中,APT 不仅是安装工具,更是基于 Debian 依赖图谱的二进制包协调器,涉及元数据校验、GPG 签名验证与服务初始化链路。理解 apt 工作原理和 postgresql 安装约束,是实现稳定连接与权限管控的基础。尤其在 Ubuntu 16.04 这类已结束支持但仍在工控、教育等场景广泛使用的 LTS 版本中,必须严格遵循官方源提供的 PostgreSQL 9.5 版本,规避手动混装导致的协议

weixin_30652897的博客 407

Rails生产环境为何必须从SQLite切换到PostgreSQL

SQLite作为嵌入式数据库,采用文件级锁和动态类型机制,适合开发阶段快速迭代;而PostgreSQL提供行级锁、MVCC并发控制、严格数据类型与JSONB原生支持,是支撑高并发Web应用的工业级选择。其连接池友好性、系统级服务管理能力及与Ubuntu 18.04 LTS生态深度集成的特性,使其成为Rails生产部署的事实标准。在日活数千、评论点赞频繁、需全文检索与实时查询的典型业务场景中,PostgreSQL不仅解决ActiveRecord::ConnectionTimeoutError等稳定性问题,更通

weixin_34246551的博客 875

PostgreSQL - 常用聚合函数:SUM_COUNT_AVG 的高级用法

PostgreSQL 聚合函数高级用法摘要 PostgreSQL 提供了 SUM、COUNT、AVG 等聚合函数的高级特性,包括窗口函数、条件聚合和分组集等功能。本文重点介绍了三种实用技巧: FILTER 子句 - 实现条件聚合的优雅方式,比传统 CASE WHEN 更清晰高效。示例展示了如何统计不同区域销售额和订单数。 窗口函数 - 支持不改变行数的聚合计算,适用于累计求和、移动平均等场景。具体案例包括计算累计销售额、分组内平均价格和订单金额占比。 Java 集成 - 通过 JPA Native Quer

千淘万漉虽辛苦,吹尽狂沙始到金 2万+
上一篇: Python_day19(2018.7.27)-(抽象类,接口类,多态,封装)
下一篇: TypeScript 之类型判断
weixin_33692284
博客等级 码龄11年 5694粉丝 1368原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值