PostgreSQL码农集散地

用AI改内核代码靠谱吗?入库性能居然提升300%

参考文档点击文末阅读原文打开; 推荐《最好的PostgreSQL学习镜像》;


穷鬼玩PolarDB RAC系列 | pg_bulkload适配PFS接口加速300%批量导入

穷鬼玩PolarDB RAC一写多读集群系列已经写了几篇:

  • 《在Docker容器中用loop设备模拟共享存储》
  • 《如何搭建PolarDB容灾(Standby)节点》
  • 《共享存储在线扩容》
  • 《计算节点 Switchover》
  • 《在线备份》
  • 《在线归档》
  • 《实时归档》
  • 《时间点恢复(PITR)》
  • 《读写分离》
  • 《主机全毁, 只剩共享存储的PolarDB还有救吗?》
  • 《激活容灾(Standby)节点》
  • 《将“共享存储实例”转换为“本地存储实例”》
  • 《将“本地存储实例”转换为“共享存储实例”》
  • 《升级vector插件》
  • 《使用图数据库插件AGE》
  • 《接入私有化大模型服务》
  • 《接入PostGIS插件全功能》
  • 《接入pg_duckdb支持数据湖功能,且OLAP性能数量级提升》

本篇文章介绍一下如何修改pg_bulkload, 适配PFS, 加速批量导入PolarDB数据库. 实验环境依赖 《在Docker容器中用loop设备模拟共享存储》 , 如果没有环境, 请自行参考以上文章搭建环境.

pg_bulkload是PostgreSQL加速逻辑数据导入的工具, 可以绕过wal, shared_buffer, 并且支持并行、支持使用binary方式(绕过PG datatype序列化和反序列化过程)直接写入PostgreSQL数据文件. 实现几倍于copy的导入性能.  但是PolarDB的数据文件存放于PFS内, 读写接口都改成了pfs接口, pg_bulkload无法直接使用, 在PolarDB 11版本内通过如下方式进行修改, 支持了本地盘使用。pg_bulkload, 但还没有在pfs上尝试过, 本文将使用PolarDB 15开源版进行尝试. 老规矩,让AI来适配代码。

  • 《PolarDB 100 问 | PolarDB 11 编译 pg_bulkload 插件报错》
  • 《PolarDB 100 问 | PolarDB 11 使用 pg_bulkload 插件导入数据报错》
  • 《PostgreSQL 数据传输&存储 数据的序列化和反序列化 (serialization/deserialization)》

pg_bulkload 适配PFS

有了前面的背景介绍, 我们可以直接修改writer_direct.c, 参看如下pfs头文件:

$ ll PolarDB-for-PostgreSQL/src/include/storage/polar*  
-rw-r--r--  1 digoal  staff   3.3K Dec 20 15:24 polar_bufmgr.h  
-rw-r--r--  1 digoal  staff   3.9K Dec 20 15:24 polar_copybuf.h  
-rw-r--r--  1 digoal  staff    13K Dec 20 15:24 polar_fd.h  
-rw-r--r--  1 digoal  staff   3.4K Dec 20 15:24 polar_flush.h  
-rw-r--r--  1 digoal  staff   5.6K Dec 20 15:24 polar_io_stat.h  
-rw-r--r--  1 digoal  staff   3.4K Dec 20 15:24 polar_lock_stats.h  
-rw-r--r--  1 digoal  staff   7.9K Dec 20 15:24 polar_procpool.h  
-rw-r--r--  1 digoal  staff   5.3K Dec 20 15:24 polar_rsc.h  
-rw-r--r--  1 digoal  staff   5.5K Dec 20 15:24 polar_xlogbuf.h  

$ ll PolarDB-for-PostgreSQL/src/include//polar_vfs/*  
-rw-r--r--   1 digoal  staff   1.2K Dec 20 15:24 polar_bufferio.h  
-rw-r--r--   1 digoal  staff   2.3K Dec 20 15:24 polar_directio.h  
-rw-r--r--   1 digoal  staff   1.5K Dec 20 15:24 polar_pfsd.h  
-rw-r--r--   1 digoal  staff   2.2K Dec 20 15:24 polar_vfs_fe.h  
-rw-r--r--   1 digoal  staff   3.4K Dec 20 15:24 polar_vfs_interface.h  

进入pb1 容器

docker exec -ti pb1 bash  

克隆代码

cd /data  
git clone -c core.symlinks=true --depth 1 https://github.com/ossc-db/pg_bulkload   

过程略,把使用过程中的报错和头文杰告知AI让它来改,最好修改如下, 替换了一些write,BasicOpenFilePerm,fsync,lseek接口为pfs的对应接口.

$ diff pg_bulkload_for_polar/lib/writer_direct.c pg_bulkload/lib/writer_direct.c   
8d7  
< #include "storage/polar_fd.h"  
223c222  
<   self->lsf_fd = polar_open(self->lsf_path,  
---  
>   self->lsf_fd = BasicOpenFilePerm(self->lsf_path,  
233,234c232,233  
<   if (polar_write(self->lsf_fd, ls, sizeof(LoadStatus)) != sizeof(LoadStatus) ||  
<     polar_fsync(self->lsf_fd) != 0)  
---  
>   if (write(self->lsf_fd, ls, sizeof(LoadStatus)) != sizeof(LoadStatus) ||  
>     pg_fsync(self->lsf_fd) != 0)  
629c628  
<       int len = polar_write(loader->datafd, buffer + written, total);  
---  
>       int len = write(loader->datafd, buffer + written, total);  
695c694  
<   fd = polar_open(fname, O_CREAT | O_WRONLY | PG_BINARY, S_IRUSR | S_IWUSR);  
---  
>   fd = BasicOpenFilePerm(fname, O_CREAT | O_WRONLY | PG_BINARY, S_IRUSR | S_IWUSR);  
702c701  
<   ret = polar_lseek(fd, BLCKSZ * (blknum % RELSEG_SIZE), SEEK_SET);  
---  
>   ret = lseek(fd, BLCKSZ * (blknum % RELSEG_SIZE), SEEK_SET);  
726c725  
<     if (polar_fsync(loader->datafd) != 0)  
---  
>     if (pg_fsync(loader->datafd) != 0)  
729c728  
<     if (polar_close(loader->datafd) < 0)  
---  
>     if (close(loader->datafd) < 0)  
750,751c749,750  
<   polar_lseek(loader->lsf_fd, 0, SEEK_SET);  
<   ret = polar_write(loader->lsf_fd, ls, sizeof(LoadStatus));  
---  
>   lseek(loader->lsf_fd, 0, SEEK_SET);  
>   ret = write(loader->lsf_fd, ls, sizeof(LoadStatus));  
756c755  
<   if (polar_fsync(loader->lsf_fd) != 0)  
---  
>   if (pg_fsync(loader->lsf_fd) != 0)  

编译AI修改后的pg_bulkload

cd /data/pg_bulkload  
sudo chown -R postgres:postgres /home/postgres/tmp_polardb_pg_15_base  
USE_PGXS=1 make install  

安装pg_bulkload插件

$ psql  
psql (PostgreSQL 15.10 (PolarDB 15.10.2.0 build d4f5477d debug) on aarch64-linux-gnu)  
Type "help"forhelp.  

postgres=# create extension pg_bulkload ;  

使用pg_bulkload导入PolarDB 15 on PFS举例

1、参考满哥的这篇文章( https://www.modb.pro/db/1754101551677394944 ), 创建一张foo表, 生成一些测试数据, 并使用pg_bulkload命令行往PolarDB foo表进行导入.

进入pb1 容器

docker exec -ti pb1 bash  

2、在PolarDB中建表

create table foo(a int, b varchar);    

3、生成点数据

cd /data/pg_bulkload    

seq 100000| awk '{print $0",foo"}' > foo.csv    

4、使用pg_bulkload命令行往PolarDB 15 foo表进行导入

$ pg_bulkload -i ./foo.csv -O foo -l test_foo.log -p 5432 -o "TYPE=csv" -o "DELIMITER=," -d postgres -U postgres    
NOTICE: BULK LOAD START  
NOTICE: BULK LOAD END  
  0 Rows skipped.  
  100000 Rows successfully loaded.  
  0 Rows not loaded due to parse errors.  
  0 Rows not loaded due to duplicate errors.  
  0 Rows replaced with new rows.  

5、pg_bulkload通过direct模式导入的数据需要重启才能被看到, 和PolarDB relation size cache mode有关(11 对应这个参数 polar_nblocks_cache_mode).

postgres=# select count(*) from foo;  
 count   
-------  
     0  
(1 row)  

# 重启PolarDB  
pg_ctl restart -m fast -D ~/primary  

postgres=# select count(*) from foo;  
 count    
--------  
 100000  
(1 row)  

PolarDB 15可以通过polar_enable_rel_size_cache参数来控制.

postgres=# alter system set polar_enable_rel_size_cache=off;
ALTER SYSTEM

# 重启PolarDB  
pg_ctl restart -m fast -D ~/primary  

关闭polar_enable_rel_size_cache后, pg_bulkload导入的数据可以立即被看见.

6、检查一下数据文件是不是写在pfs里?

postgres=# select pg_relation_filepath('foo');  
        pg_relation_filepath          
------------------------------------  
 /nvme1n1/shared_data//base/5/24692  
(1 row)  

没错

$ pfs -C disk stat /nvme1n1/shared_data//base/5/24692  
  file: /nvme1n1/shared_data//base/5/24692  
  size: 3629056         blocks: 8192  
device: pbd-0   inode: 658 links: 1  
access: 0, Thu Jan  1 08:00:00 1970  
modify: 1735801813, Thu Jan  2 15:10:13 2025  
change: 1735801813, Thu Jan  2 15:10:13 2025  

7、使用1000万数据对比, pg_bulkload速度是COPY 3倍多.

$ time pg_bulkload -i ./foo.csv -O foo -l test_foo.log -p 5432 -o "TYPE=csv" -o "DELIMITER=," -d postgres -U postgres  
NOTICE: BULK LOAD START
NOTICE: BULK LOAD END
  0 Rows skipped.
  10000000 Rows successfully loaded.
  0 Rows not loaded due to parse errors.
  0 Rows not loaded due to duplicate errors.
  0 Rows replaced with new rows.

real  0m4.172s
user  0m0.002s
sys 0m0.011s

postgres=# \copy foo from './foo.csv' with (format csv);
COPY 10000000
Time: 14377.082 ms (00:14.377)

参考

《穷鬼玩PolarDB RAC一写多读集群系列 | 在Docker容器中用loop设备模拟共享存储》

《穷鬼玩PolarDB RAC一写多读集群系列 | 如何搭建PolarDB容灾(Standby)节点》

《穷鬼玩PolarDB RAC一写多读集群系列 | 共享存储在线扩容》

《穷鬼玩PolarDB RAC一写多读集群系列 | 计算节点 Switchover》

《穷鬼玩PolarDB RAC一写多读集群系列 | 在线备份》

《穷鬼玩PolarDB RAC一写多读集群系列 | 在线归档》

《穷鬼玩PolarDB RAC一写多读集群系列 | 实时归档》

《穷鬼玩PolarDB RAC一写多读集群系列 | 时间点恢复(PITR)》

《穷鬼玩PolarDB RAC一写多读集群系列 | 读写分离》

《穷鬼玩PolarDB RAC一写多读集群系列 | 主机全毁, 只剩共享存储的PolarDB还有救吗?》

《穷鬼玩PolarDB RAC一写多读集群系列 | 激活容灾(Standby)节点》

《穷鬼玩PolarDB RAC一写多读集群系列 | 将“共享存储实例”转换为“本地存储实例”》

《穷鬼玩PolarDB RAC一写多读集群系列 | 将“本地存储实例”转换为“共享存储实例”》

《穷鬼玩PolarDB RAC一写多读集群系列 | 升级vector插件》

《穷鬼玩PolarDB RAC一写多读集群系列 | 使用图数据库插件AGE》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入私有化大模型服务》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入PostGIS插件全功能》

《穷鬼玩PolarDB RAC一写多读集群系列 | 接入pg_duckdb支持数据湖功能,且OLAP性能数量级提升》

文末彩蛋:国产数据库周边生态

当然一款数据库要流行起来, 除了自己要强大, 还离不开生态. 用好周边生态工具, 管理水平战胜90%老司机!!! 下面简单介绍一下国产数据库周边生态.

1、管控软件

鸣嵩(前阿里云数据库总经理 / 研究员)等大佬们创业创办的云猿生, 核心产品是KubeBlocks. 他们的理念是让管理数据库和搭积木一样简单, 如果你要管理很多套并且种类(OLTP\OLAP\NoSQL\KV\TS\MQ等)很多的数据库产品, 推荐首选.

  • https://github.com/apecloud/kubeblocks

PG中文社区核心委员唐成老师的公司乘数开源的Clup, 专用管理PostgreSQL和PolarDB的集群管理软件, 如果你要管理很多套数据库, 推荐选择. 并且Clup还提供了企业版、自研的连接池、分布式存储、一体机、备份平台等, 是企业用户推荐之选.

  • https://www.csudata.com/

若航老司机开源的pigsty, 集成了300多个PG插件的PG集群和PolarDB集群管理软件, 如果你要管理很多套PG或PolarDB数据库, 且对插件有特别多的需求, 推荐选择.

  • https://pigsty.cc/zh/

2、审计监控诊断优化

翟总(曾经是我背后的男人)到海信聚好看后研发的 DBdoctor, 采用ebpf技术, 在对数据库几乎没有影响的情况下实时监控数据库和服务器的各项指标, 发现和诊断问题根因非常方便.

  • https://www.dbdoctor.cn/

天舟老哥的核心产品Bytebase 是位于您和数据库之间的中间件。它是数据库 DevOps 的 GitLab/GitHub,专为开发人员、DBA 和平台工程师打造。

  • https://bytebase.cc/docs/introduction/what-is-bytebase/

PawSQL, SQL优化和诊断产品.  

D-Smart, Oracle老前辈白老大出品, 专注企业级市场, 将业界顶级DBA经验的产品化作品, 产品功能包括数据库监控、诊断、优化等.

  • https://www.modb.pro/db/567140

3、国产数据库IDE

IDE是开发者的必备工具,例如社区有pgAdmin, 国产IDE则可以看看老程序猿达刚老师的DeskUI:

  • https://www.deskui.com

4、数据同步&迁移&备份恢复

NineData, 老领导出去创业做的产品, 产品涵盖了数据同步、迁移、备份、比对、devops、chatDBA等.

  • https://www.ninedata.cloud/home

DSG, 非常老牌的数据库同步迁移企业级产品, 支持各种数据库的异构和同构迁移, 用他们的话说, 没有dsg搞不定的迁移, 比goldengate还牛.

  • https://www.dsgdata.com/

公开课

如果你对PolarDB学习感兴趣可以阅读这个公开课系列:

除了PolarDB还非常值得关注的几款PG栈国产数据库:

  • HaloDB(基于PG兼容PostgreSQL、Oracle、MySQL. http://www.halodbtech.com/ )、
  • IvorySQL(基于开源PG兼容PG、Oracle. https://www.ivorysql.org/zh-cn/ )、
  • ProtonBase(云原生分布式数仓. https://protonbase.com/ )、
  • 成都文武数据库(https://ww-it.cn)

参考文档点击阅读原文获得


感谢关注我的github (https://github.com/digoal/blog) 及视频号:

Image