PostgreSQL pgbench tpcb 海量数据库测试 - 分区表测试优化

简介: 标签PostgreSQL , pgbench , tpcb背景pgbench是PG的一款测试工具,内置的测试CASE为tpcb测试。同时支持用户自己写测试CASE。大量自定义CASE参考https://github.com/digoal/blog/blob/master/201711/readme.md当我们使用tpcb测试CASE时,如果生成的数据量过于庞大,例如我最近在生成1万亿的CASE,可以考虑使用分区表,但是目前PG内置分区表的性能在分区非常多时,使用PREPARED STATEMENT会导致性能下降。

标签

PostgreSQL , pgbench , tpcb


背景

pgbench是PG的一款测试工具,内置的测试CASE为tpcb测试。同时支持用户自己写测试CASE。

大量自定义CASE参考

https://github.com/digoal/blog/blob/master/201711/readme.md

当我们使用tpcb测试CASE时,如果生成的数据量过于庞大,例如我最近在生成1万亿的CASE,可以考虑使用分区表,但是目前PG内置分区表的性能在分区非常多时,使用PREPARED STATEMENT会导致性能下降。

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

建议使用pg_pathman分区插件,消除这个性能问题。

或者可以把pgbench的SQL改一下,使用udf,动态SQL来实现,性能依旧杠杠的。

pgbench tpcb 分区表 UDF动态SQL实现

1、原生QUERY如下

读写case

\set aid random(1, 100000 * :scale)  
\set bid random(1, 1 * :scale)  
\set tid random(1, 10 * :scale)  
\set delta random(-5000, 5000)  
BEGIN;  
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;  
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;  
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;  
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;  
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);  
END;  

只读case

\set aid random(1, 100000 * :scale)  
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;  

tpcb pgbench_accounts 分区表重构

1、定义结构

例如1万亿

pgbench -i -I dt --tablespace=tbs1 -s 10000000  

2、使用分区

create table p (like pgbench_accounts) partition by RANGE ( aid ) tablespace tbs1;  

3、创建4097个分区,每个分区244140625条记录

do language plpgsql $$                                                           
declare  
  i_rows_perpartition int8 := 244140625;  
begin  
  for i in 0..4096 loop  
    execute format ('create table pgbench_accounts%s partition of p for values from (%s) to (%s) tablespace tbs1', i, i*i_rows_perpartition, (i+1)*i_rows_perpartition);  
  end loop;  
end;  
$$;  

4、重命名表

drop table pgbench_accounts;  
  
alter table p rename to pgbench_accounts;  
  
-- alter table pgbench_accounts add constraint pk_pgbench_accounts_aid primary key (aid) using index tablespace tbs2;  

5、新建任务表,并行加载数据

drop table task;  
create table task(id int primary key);  
insert into task select i from generate_series(0,4095) t(i);  

6、新建基础数据表,写入244140625条数据。

create table init_accounts(aid int8);  
insert into init_accounts select generate_series(0,244140624);  

7、创建UDF,调用一次,往单个分区中写入244140625条数据.

create or replace function tpcb_init_accounts() returns void as $$  
declare  
  v_id int;  
begin  
  with tmp as (select * from task limit 1 for update skip locked),  
    tmp1 as (delete from task using tmp where task.id=tmp.id)  
    select id into v_id from tmp;  
    
  if found then  
    execute format ('insert into pgbench_accounts%s select aid+%s*244140625::int8, ((aid+%s*244140625::int8)-1)/100000 + 1, 0 from init_accounts on conflict do nothing', v_id, v_id, v_id);  
  end if;  
end;  
$$ language plpgsql strict;  

8、使用pgbench,开启64个并发,生成1万亿条tpcb pgbench_accounts测试数据。

vi test.sql  
select tpcb_init_accounts();  
  
nohup pgbench -M prepared -n -r -f ./test.sql -c 64 -j 64 -t 100 >./init.log 2>&1 &  

9、创建任务表,用于生成pgbench_accounts分区表PK

drop table task;  
create table task(id int primary key);  
insert into task select i from generate_series(0,4095) t(i);  

10、新建UDF,用于生成pgbench_accounts分区表PK

create or replace function tpcb_init_accounts_pkey() returns void as $$  
declare  
  v_id int;  
begin  
  with tmp as (select * from task limit 1 for update skip locked),  
    tmp1 as (delete from task using tmp where task.id=tmp.id)  
    select id into v_id from tmp;  
    
  if found then  
    execute format ('analyze pgbench_accounts%s', v_id);  
    execute format ('alter table pgbench_accounts%s add constraint pk_pgbench_accounts%s_aid primary key (aid) using index tablespace tbs2', v_id, v_id);  
  end if;  
end;  
$$ language plpgsql strict;  

11、生成pgbench_accounts分区表PK

vi test.sql  
select tpcb_init_accounts_pkey();  
  
nohup pgbench -M prepared -n -r -f ./test.sql -c 64 -j 64 -t 100 >./init.log 2>&1 &  

如果使用的是pg_pathman插件,不用这么麻烦。

1、使用pgbench生成结构

pgbench -i -I dt --tablespace=tbs1 -s 10000000  

2、转换为分区表

https://github.com/postgrespro/pg_pathman

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

3、使用pgbench生成数据

pgbench -i -I g -n --tablespace=tbs1 -s 10000000  

4、新增PK

表级parallel  
  
analyze 表  
  
pgbench -i -I p -n -s 10000000 --index-tablespace=tbs2  

tpcb UDF

1、读写

create or replace function tpcb_rw(     
  i_aid int8,     
  i_bid int4,     
  i_tid int4,     
  i_delta int4,     
  i_rows_perpartition int8     
) returns int as $$    
declare    
  i_suffix int := i_aid/i_rows_perpartition;     
  res int;     
begin    
  execute format('execute p1_%s(%s,%s)', i_suffix, i_delta, i_aid);    
  execute format('execute p2_%s(%s)', i_suffix, i_aid) into res;    
  UPDATE pgbench_tellers SET tbalance = tbalance + i_delta WHERE tid = i_tid;    
  UPDATE pgbench_branches SET bbalance = bbalance + i_delta WHERE bid = i_bid;    
  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (i_tid, i_bid, i_aid, i_delta, CURRENT_TIMESTAMP);    
  return res;    
exception when others then    
  execute format('prepare p1_%s(int,int8) as UPDATE pgbench_accounts%s SET abalance = abalance + $1 WHERE aid = $2', i_suffix, i_suffix);    
  execute format('prepare p2_%s(int8) as SELECT abalance FROM pgbench_accounts%s WHERE aid = $1', i_suffix, i_suffix);    
  execute format('execute p1_%s(%s,%s)', i_suffix, i_delta, i_aid);    
  execute format('execute p2_%s(%s)', i_suffix, i_aid) into res;    
  return res;    
end;    
$$ language plpgsql strict;     

2、只读

create or replace function tpcb_ro(     
  i_aid int8,     
  i_rows_perpartition int8     
) returns int as $$    
declare    
  i_suffix int := i_aid/i_rows_perpartition;    
  res int;    
begin    
  execute format('execute p2_%s(%s)', i_suffix, i_aid) into res;    
  return res;    
exception when others then    
  execute format('prepare p2_%s(int8) as SELECT abalance FROM pgbench_accounts%s WHERE aid = $1', i_suffix, i_suffix);    
  execute format('execute p2_%s(%s)', i_suffix, i_aid) into res;    
  return res;    
end;    
$$ language plpgsql strict;     

3、改成自定义脚本

读写CASE

vi rw.sql  
  
\set aid random(1, 100000 * :scale)  
\set bid random(1, 1 * :scale)  
\set tid random(1, 10 * :scale)  
\set delta random(-5000, 5000)  
SELECT tpcb_rw(:aid,:bid,:tid,:delta,244140625);  

只读case

vi ro.sql  
  
\set aid random(1, 100000 * :scale)  
SELECT tpcb_ro(:aid,244140625);  

参考

https://github.com/digoal/blog/blob/master/201711/readme.md

https://github.com/postgrespro/pg_pathman

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

《PostgreSQL Oracle 兼容性之 - DBMS_SQL(存储过程动态SQL中使用绑定变量-DB端prepare statement)》

https://www.postgresql.org/docs/devel/static/pgbench.html

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=60e612b602999e670f2d57a01e52799eaa903ca9

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
SQL 存储 Oracle
跨库迁移有多难?我们用 YashanDB YMP 做了个测试,效果惊艳了
异构数据库迁移常被视为企业数字化转型中的难题,涉及SQL兼容性、对象依赖顺序与数据一致性等关键环节。YashanDB Migration Platform(YMP)通过实际测试展示了卓越能力,从Oracle到YashanDB的迁移表现超预期。其亮点包括:零脚本全自动迁移逻辑、全面支持复杂对象(如存储过程、触发器)、高性能迁移速度远超传统方案。YMP提供评估、SQL转换、对象迁移、数据校验及可视化全流程管理,为企业平滑过渡至国产数据库提供了可靠选择。
跨库迁移有多难?我们用 YashanDB YMP 做了个测试,效果惊艳了
|
存储 关系型数据库 测试技术
拯救海量数据:PostgreSQL分区表性能优化实战手册(附压测对比)
本文深入解析PostgreSQL分区表的核心原理与优化策略,涵盖性能痛点、实战案例及压测对比。首先阐述分区表作为继承表+路由规则的逻辑封装,分析分区裁剪失效、全局索引膨胀和VACUUM堆积三大性能杀手,并通过电商订单表崩溃事件说明旧分区维护的重要性。接着提出四维设计法优化分区策略,包括时间范围分区黄金法则与自动化维护体系。同时对比局部索引与全局索引性能,展示后者在特定场景下的优势。进一步探讨并行查询优化、冷热数据分层存储及故障复盘,解决分区锁竞争问题。
1840 2
|
存储 人工智能 编译器
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
1149 11
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
|
JavaScript Java 测试技术
大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)
大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)
503 0
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
334 1
|
资源调度 前端开发 JavaScript
React 测试库 React Testing Library
【10月更文挑战第22天】本文介绍了 React Testing Library 的基本概念和使用方法,包括安装、基本用法、常见问题及解决方法。通过代码案例详细解释了如何测试 React 组件,帮助开发者提高应用质量和稳定性。
639 1
|
测试技术 开发工具 Python
在Jetson Nano上编译 pyrealsense2库包,并在Intel的tof相机上进行测试
在Jetson Nano上编译 pyrealsense2库包,并在Intel的tof相机上进行测试
1085 0
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
388 0
|
关系型数据库 MySQL Python
[python]使用faker库生成测试数据
[python]使用faker库生成测试数据
466 3
|
监控 Oracle 关系型数据库
关系型数据库Oracle恢复测试
【7月更文挑战第20天】
514 7

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多