前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PostgreSQL解决数据膨胀问题pg_repack

PostgreSQL解决数据膨胀问题pg_repack

作者头像
shysh95
发布2023-11-20 11:24:17
2610
发布2023-11-20 11:24:17
举报
文章被收录于专栏:shysh95shysh95

Hi~朋友,关注置顶防止错过消息

pg自带工具

为了解决数据膨胀,pg自身提供了vacuum工具,vacuum分为普通vacuum和vacuum full。

普通vacuum会清理死元组,但是不会进行空间重组,磁盘上的空间不会释放,会释放死元组的空间,后续的插入会根据空闲空间管理fsm优先插入空闲空间。

vacuum full会清理释放磁盘空间,但是获取的锁级别较高,它是通过新建一个表空间,然后从老表拷贝数据到新文件中,整个过程会阻塞select。

为什么需要重构表

在我们的使用场景中,有部分表记录了大量的数据,而且在列上会有大字端,导致磁盘占用量很大,我们通过delete将部分数据进行删除,用来释放一部分磁盘空间,同时由于这些表重构时间比较长,我们不可能选择vacuum full的方式,因为这会导致我们的服务长期不可用。

如何避免重构表期间对业务的长时间影响

为了避免影响业务,pg社区开发了pgrepack 工具,该工具以extension的形式存在,用户可以通过create extensiton pg_repack命令在数据库中安装该插件。

pg_repack安装

首先你需要准备一台可以连接数据库的服务器,在服务器上安装repack工具包,这个地方安装的repack工具包需要和数据库的插件对应,如果对应不正确,在执行pg_repack命令的时候会报错,这个时候大家就需要调整repack工具包的版本。

代码语言:javascript
复制
sudo apt install postgresql-12-repack

pg_repack执行前的准备

  1. 磁盘空间要预留出足够的空间,假设你重构的表占用空间是10GB,起码你要留出10GB的空间(这里还不考虑数据一直在写入磁盘空间可用越来越少的情况)
  2. 修改数据库的idle_in_transaction_session_timeout参数,如果你有很大的表需要repack,请一定要调大该参数。

idle_in_transaction_session_timeout用来控制事务执行时长,单位是ms,当事务闲置(状态为idle in transaction)时间超过该参数的设置时,会被PostgresSQL杀掉。

pg_repack执行

代码语言:javascript
复制
pg_repack -h 数据库地址 -p 数据库端口号 --jobs 2--table 表名 --no-order -d 数据库名称 -U 数据库用户 -k

上面的命令是我在实际执行pg_repack的时候操作,具体参数的含义大家可以参考官方文档。

pg_repack的执行过程

pg_repack插件会在库里面创建repack的schema,里面有两张表:

  • tables:记录创建trigger以及一些要执行的SQL语句
  • primary_keys:里面包含indrelid和indexrelid,分别代表表的oid和主键或者唯一索引的 oid

在这里可以看出,被repack的表至少存在一个主键或者唯一索引

在tables里面的SQL顺序代表pg_repack所要执行的SQL的顺序,整个repack过程只有极少阶段需要独占锁,其他步骤只需要在原始表上增加一个ACCESS SHARE锁,DML可以正常执行,但DDL不可以执行(除了VACUUM和ANALYZE)。

  1. 创建一个新的数据类型
代码语言:javascript
复制
-- pg_后面的数字一般就是表的oid
 
CREATE TYPE repack.pk_195075 AS (id bigint)

2. 创建一个新的表,用来记录表在重构时被重构表的增量数据,这里需要独占锁,但时间很短

代码语言:javascript
复制
-- row列就是变更的行记录
 
CREATE TABLE repack.log_195075 (id bigserial PRIMARY KEY, pk repack.pk_195075, row public.表名)

3. 创建一个触发器,用来捕获repack期间表的所有的变更记录,这里需要独占锁,但时间很短,并且启动触发器

代码语言:javascript
复制
CREATE TRIGGER repack_trigger
 
    AFTER INSERT OR DELETE OR UPDATE
 
    ON public.表名
 
    FOR EACH ROW
 
EXECUTE PROCEDURE repack.repack_trigger(
 
'INSERT INTO repack.log_195075(pk, row) VALUES( CASE WHEN  
1
I
S
N
U
L
L
T
H
E
N
N
U
L
L
E
L
S
E
(
R
O
W
(
 1.id)::repack.pk_195075) END, 


 
--启动触发器
 
ALTER TABLE public.表名 ENABLE ALWAYS TRIGGER repack_trigger

4. 创建一个新表,用来往其中拷贝被repack表的数据,oids=false表示不为表分配oid,表所在的表空间为pg_default,only 用来表示只扫描被repack表的本身,不扫描其后代表(pg的表实现了继承)

代码语言:javascript
复制
CREATE TABLE repack.table_195075 WITH (oids = false)
 
                                 TABLESPACE pg_default
 
AS
 
SELECT id,
 
       xxx,
 
       xxx,
 
       xxx,
 
       create_time
 
FROM ONLY public.表名
 


 
INSERT INTO repack.table_195075
 
SELECT id,
 
       xxx,
 
       xxx,
 
       xxx,
 
       create_time
 
FROM ONLY public.表名

5. 在这张新表上建立索引,当索引建立完毕以后会将repack.log_195075表中记录的日志变更应用到新表上

6. 使用系统目录交换表,包括索引和toast表,这里需要一个独占锁,但时间时间较短

7. 删除原始表

其他的大表重构方案

除了pgrepack,PostgreSQL社区还有另一款pgsqueeze工具用来处理大表的数据膨胀问题,由于我这里没有真正操作过,就不在这里详细描述了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档