目录
概述
安装
原理介绍
参数详解
普通表语法示例
分区表和继承表语法示例
索引语法示例
常见问题
概述
pg_repack插件对表空间进行重新“包装”,回收碎片空间,有效解决因对表大量更新、删除等操作引起的空间膨胀问题。pg_repack获取排它锁的时间较短,多数时间不阻塞读写,相比CLUSTER或VACUUM FULL操作更加轻量化。
安装依赖
yum install lz4-devel
安装编译
[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的实现原理如下:
创建日志表,记录repack期间对原表的变更。
在原表上创建触发器,将原表的INSERT、UPDATE和DELETE操作记录到日志表中。
创建原表结构相同的新表并将原表数据导入其中。
在新表中创建与原表相同的索引。
将日志表里的变更(即repack期间表上产生的增量数据)应用到新表。
在系统catalog交换新旧表。
删除旧表。
说明:
pg_repack会在第1、2、6、7步短暂持有原表的排它锁并阻塞读写。其余步骤pg_repack只需要持有原表的ACCESS SHARE锁,不阻塞对原表的INSERT、UPDATE和DELETE操作,但会阻塞DDL操作。
对索引进行repack的实现原理如下:
以CREATE INDEX CONCURRENTLY方式创建新索引。
在系统catalog交换新旧索引(需持有排它锁,短暂阻塞读写)。
以DROP INDEX CONCURRENTLY的方式删除旧索引。
说明:
pg_repack效果等同于REINDEX CONCURRENTLY,但是比REINDEX CONCURRENTLY更为复杂,如果使用REINDEX CONCURRENTLY,只需要一步就能完成。pg_repack支持该能力的原因是老版本的PostgreSQL不支持REINDEX CONCURRENTLY,从而只能借助pg_repack来实现。
参数详解
通用选项
-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操作。
语法说明一
通过--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参数指定分区表的表名:
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):
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表上的所有索引:
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。
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命令删除。
公众号内直接回复加群也可以,扫码加群也可以,觉得帖子写的不错,点点关注,点点赞,多多转载,请多多支持
往期帖子汇总:
数据库维护工具:数据迁移、性能监控、数据修复的全面工具汇总
PostgreSQL:从零开始学PostgreSQL