前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >从零开始学PostgreSQL-工具篇2:碎片回收pg_repack

从零开始学PostgreSQL-工具篇2:碎片回收pg_repack

作者头像
DBA实战
发布2024-10-23 16:51:49
发布2024-10-23 16:51:49
23900
代码可运行
举报
文章被收录于专栏:DBA实战DBA实战
运行总次数:0
代码可运行

概述

pg_repack插件对表空间进行重新“包装”,回收碎片空间,有效解决因对表大量更新、删除等操作引起的空间膨胀问题。pg_repack获取排它锁的时间较短,多数时间不阻塞读写,相比CLUSTER或VACUUM FULL操作更加轻量化。

安装依赖

代码语言:javascript
代码运行次数:0
运行
复制
yum install lz4-devel

安装编译

代码语言:javascript
代码运行次数:0
运行
复制
[root@test19-server07 opt]# wget https://github.com/reorg/pg_repack/archive/refs/tags/ver_1.5.1.tar.gz
shell > tar xvf ver_1.5.1.tar.gz
shell > mv pg_repack-ver_1.5.1/  pg_repack
shell > cd pg_repack
shell > export PG_CONFIG=/usr/pgsql-16/bin/pg_config
shell > make
shell > make install 

##安装扩展
[root@test19-server07 ~]# psql -U postgres -h 127.0.0.1 -p 5432 -W
Password: 
psql (16.4)
postgres=# CREATE EXTENSION pg_repack;
CREATE EXTENSION

原理介绍

pg_repack插件支持对全表和索引进行repack操作。

对全表进行repack的实现原理如下:

  1. 创建日志表,记录repack期间对原表的变更。
  2. 在原表上创建触发器,将原表的INSERT、UPDATE和DELETE操作记录到日志表中。
  3. 创建原表结构相同的新表并将原表数据导入其中。
  4. 在新表中创建与原表相同的索引。
  5. 将日志表里的变更(即repack期间表上产生的增量数据)应用到新表。
  6. 在系统catalog交换新旧表。
  7. 删除旧表。

说明:

pg_repack会在第1、2、6、7步短暂持有原表的排它锁并阻塞读写。其余步骤pg_repack只需要持有原表的ACCESS SHARE锁,不阻塞对原表的INSERT、UPDATE和DELETE操作,但会阻塞DDL操作。

对索引进行repack的实现原理如下:

  1. 以CREATE INDEX CONCURRENTLY方式创建新索引。
  2. 在系统catalog交换新旧索引(需持有排它锁,短暂阻塞读写)。
  3. 以DROP INDEX CONCURRENTLY的方式删除旧索引。

说明:

pg_repack效果等同于REINDEX CONCURRENTLY,但是比REINDEX CONCURRENTLY更为复杂,如果使用REINDEX CONCURRENTLY,只需要一步就能完成。pg_repack支持该能力的原因是老版本的PostgreSQL不支持REINDEX CONCURRENTLY,从而只能借助pg_repack来实现。

参数详解

代码语言:javascript
代码运行次数:0
运行
复制
通用选项
-a, --all: 重组所有数据库。
-t, --table=TABLE: 仅重组特定表。
-I, --parent-table=TABLE: 重组特定父表及其继承者。
-c, --schema=SCHEMA: 仅重组特定模式中的表。
-s, --tablespace=TBLSPC: 将重组后的表移动到新的表空间。
-S, --moveidx: 将重组后的索引也移动到新的表空间。
-o, --order-by=COLUMNS: 按指定列排序而不是按聚簇键排序。
-n, --no-order: 执行 VACUUM FULL 而不是 CLUSTER。
-N, --dry-run: 显示将要重组的内容,但不执行实际操作。
-j, --jobs=NUM: 为每个表使用指定数量的并行任务。
-i, --index=INDEX仅移动指定的索引。
-x, --only-indexes: 仅移动指定表的索引。
-T, --wait-timeout=SECS: 在冲突时取消其他后端的超时时间。
-D, --no-kill-backend: 超时时不杀死其他后端。
-Z, --no-analyze: 结束时不执行 ANALYZE。
-k, --no-superuser-check: 在客户端跳过超级用户检查。
-C, --exclude-extension: 不重组属于特定扩展的表。
--error-on-invalid-index: 当发现无效索引时不进行重组。
--apply-count: 在回放期间每次事务应用的元组数。
--switch-threshold: 当剩余的元组数达到该阈值时切换表。
连接选项
-d, --dbname=DBNAME: 要连接的数据库名称。
-h, --host=HOSTNAME: 数据库服务器主机或套接字目录。
-p, --port=PORT: 数据库服务器端口。
-U, --username=USERNAME: 连接用户名称。
-w, --no-password: 从不提示输入密码。
-W, --password: 强制提示输入密码。
通用选项
-e, --echo: 回显查询。
-E, --elevel=LEVEL: 设置输出消息级别。
--help: 显示帮助信息,然后退出。
--version: 显示版本信息,然后退出。

Repack普通表和分区表分区

pg_repack支持对普通表或者分区表的某个分区进行repack,其作用类似于CLUSTER或VACUUM FULL操作,清理表中多余的空闲空间,同时重建表上的索引,适用于表空间膨胀的场景

说明

  • repack表必须有主键或唯一索引。
  • 不支持对临时表进行repack操作。
  • 不支持对带有Global Index的分区进行repack操作。

语法说明一

代码语言:javascript
代码运行次数:0
运行
复制
通过--table参数指定表名,默认情况下效果等同于CLUSTER,repack过程中对之前执行过CLUSTER操作的列进行排序:
/opt/pg_repack/bin/pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-superuser-check --echo --table public.saas3

如果希望对指定的列进行排序,可以使用--order-by参数来指定列名:
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --order-by name --no-superuser-check --echo --table public.saas3
postgres=# select * from saas3;
 id |   name    |   qq   
----+-----------+--------
  2 | New Test2 | 
  4 | New Test4 | 
  1 | Test1     | 
  3 | Test3     | 
  5 | Test3     | qq1223
(5 rows)
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --order-by id --no-superuser-check --echo --table public.saas3
postgres=# select * from saas3;
 id |   name    |   qq   
----+-----------+--------
  1 | Test1     | 
  2 | New Test2 | 
  3 | Test3     | 
  4 | New Test4 | 
  5 | Test3     | qq1223
(5 rows)

如果不希望进行排序,即希望pg_repack的效果等同于VACUUM FULL,可以使用--no-order参数:
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --table public.saas3

如果数据库集群的CPU和I/O资源充裕,可以使用--jobs参数加速repack操作,它会启动多个进程并发重建索引,适用于表上有多个索引的场景:
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --jobs 3 --table public.saas3

锁冲突时等待最多 30 秒。如果在这 30 秒内锁仍未释放,pg_repack 不会终止其他后端进程,而是放弃重组操作并返回错误
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-superuser-check --echo --table public.saas3 --wait-timeout 30 --no-kill-backend

结束时不执行 ANALYZE 操作
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --jobs 3 --parent-table public.saas3 --no-analyze

重组所有数据库
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --jobs 3 --all

Repack分区表和继承表

pg_repack支持对分区表(包括声明式分区表和继承式分区表)进行操作,它会自动找到父表的所有分区,并对每个分区依次进行repack操作。适用于分区表的所有分区都存在空间膨胀的场景

语法说明二

  • 通过--parent-table参数指定分区表的表名:
代码语言:javascript
代码运行次数:0
运行
复制
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --jobs 3 --parent-table public.saas1

说明

  • 除了--parent-table参数以外,分区表的其他参数用法与普通表基本相同。
  • 如果只是单个分区存在空间膨胀,则无需对整个分区表进行repack,使用语法说明一中(--table参数)对单个分区进行repack操作即可。
  • 不支持对带有Global Index的分区表进行repack操作。

Repack索引

pg_repack支持仅对索引进行repack操作,它的作用是重建索引,清理索引中的空闲空间,适用于索引空间膨胀的场景

说明

  • 如果索引空闲空间过多,推荐使用REINDEX CONCURRENTLY进行在线索引重建,无需使用pg_repack。pg_repack支持该能力的原因是老版本的PostgreSQL不支持REINDEX CONCURRENTLY,从而只能借助pg_repack来实现。
  • 由于pg_repack社区的特性,暂不支持对声明式分区表进行repack索引的操作,同样可以使用REINDEX CONCURRENTLY来代替。

语法说明三

  • 使用--index参数指定需要repack的索引名(saas3_pkey):
代码语言:javascript
代码运行次数:0
运行
复制
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres  --no-superuser-check --echo --index  public.saas3_pkey
  • 使用--only-indexes参数repack表上的所有索引:
代码语言:javascript
代码运行次数:0
运行
复制
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres  --no-superuser-check --echo --only-indexes --table public.saas3

常见问题

Dry Run

正式执行pg_repack之前建议使用--dry-run选项运行一次,该选项不操作表中的数据,仅验证命令是否合法、流程是否可以跑通。待命令验证成功后,再去掉该选项正式运行pg_repack。

代码语言:javascript
代码运行次数:0
运行
复制
pg_repack -U postgres -h 127.0.0.1 -p 5432 -W -d postgres --no-order --no-superuser-check --echo --jobs 3 --parent-table public.saas3 --dry-run

权限问题

  • 必须使用高权限账号运行pg_repack,不能以普通账号身份运行,否则会报错:must be polar_superuser or superuser to use xx function。
  • 如果遇到You must be a superuser to use pg_repack报错,则需要在pg_repack命令中增加--no-superuser-check选项来绕过超级用户检查。

残留对象清理

如果pg_repack在执行过程中异常退出,则repack失败,被repack的表上可能残留了repack过程中创建的对象,需要及时清理,否则可能影响表的使用:

  • 被repack的表上可能残留repack_trigger触发器,需要使用DROP TRIGGER命令删除。
  • 被repack的表上可能残留临时索引index_<oid>,需要使用DROP INDEX CONCURRENTLY命令删除。
  • repack模式下残留临时表repack_<oid>与日志表log_<oid>,需要使用DROP TABLE命令删除。
  • repack模式下残留新的类型pk_<oid>,需要使用DROP TYPE命令删除。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA实战 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档