PolarDB PostgreSQL版支持通过pg_repack插件对表空间进行重新“包装”,回收碎片空间,有效解决因对表大量更新、删除等操作引起的空间膨胀问题。pg_repack获取排它锁的时间较短,多数时间不阻塞读写,相比CLUSTER或VACUUM FULL操作更加轻量化。
前提条件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本14.10.16.0及以上)
PostgreSQL 11(内核小版本1.1.36及以上)
您可通过如下语句查看PolarDB PostgreSQL版的内核小版本的版本号:
PostgreSQL 14
select version();
PostgreSQL 11
show polar_version;
注意事项
目前pg_repack仅支持PolarDB PostgreSQL版,不支持PolarDB PostgreSQL版(兼容Oracle)。
不支持使用
-s
/--tablespace
选项对指定的tablespace进行repack操作,因为PolarDB PostgreSQL版不支持用户直接创建tablespace,而是使用默认的tablespace。不支持使用
-a
/--all
选项repack所有的数据库。不支持repack整个数据库,必须通过
--table
/--parent-table
/--index
选项指定需要repack的表或者索引。不支持使用
-c
/--schema
选项repack整个schema。在使用pg_repack工具之前需要先进行数据备份。
pg_repack会占用较大的磁盘I/O,使用前请评估是否会影响业务。以PL1级别的ESSD云盘为例,对一个100 GB的表进 repack时会达到I/O吞吐上限(250 MB/s)。
原理介绍
pg_repack插件支持对全表和索引进行repack操作。
对全表进行repack的实现原理如下:
创建日志表,记录repack期间对原表的变更。
在原表上创建触发器,将原表的
INSERT
、UPDATE
和DELETE
操作记录到日志表中。创建原表结构相同的新表并将原表数据导入其中。
在新表中创建与原表相同的索引。
将日志表里的变更应用到新表。
在系统catalog交换新旧表。
删除旧表。
说明pg_repack会在第1、2、6、7步短暂持有原表的ACCESS EXCLUSIVE锁。其余步骤pg_repack只需要持有原表的ACCESS SHARE锁,不阻塞对原表的
INSERT
、UPDATE
和DELETE
操作,但会阻塞DDL
操作。pg_repack需要额外的存储空间来保存新表和日志表,因此剩余存储空间大小需要至少是被repack表大小的两倍。
对带有Global Index的表进行repack操作会有较长时间持有排它锁并阻塞
DML
,不建议对这种表进行repack操作。不支持对临时表进行repack操作。
对索引进行repack的实现原理如下:
以
CONCURRENTLY
方式创建新索引。在系统catalog交换新旧索引。
删除旧索引。
说明如果索引空闲空间过多,推荐采用
REINDEX CONCURRENTLY
进行在线索引重建,而无需使用pg_repack
,因为pg_repack
也是基于该原理实现的。对Global Index进行repack会有较长时间持有排它锁并阻塞
DML
,不建议对该类索引进行repack操作。不支持对GiST索引进行repack操作。
使用方法
pg_repack以安装在PolarDB PostgreSQL版侧的插件作为服务端,并提供专用的客户端给用户,两者需要搭配使用。
安装插件
CREATE EXTENSION pg_repack;
查看插件版本。
SELECT extversion FROM pg_extension WHERE extname = 'pg_repack';
如果已经安装了老版本插件,可以通过先卸载原有插件再重新创建的方式来升级到最新版。
DROP EXTENSION pg_repack;
CREATE EXTENSION pg_repack;
安装客户端
pg_repack客户端工具随PolarDB-Tools工具包发布,下载安装PolarDB-Tools后即可使用其中的pg_repack客户端。下载地址及安装方法请参见PolarDB-Tools。
pg_repack客户端的版本必须匹配pg_repack插件的版本,否则无法使用。
上述下载地址只提供最新版的pg_repack客户端,如果pg_repack插件版本落后于客户端工具的版本,则需要升级插件版本。
如果插件版本升级后仍然低于客户端版本,则需要先在用户控制台进行PolarDB PostgreSQL版内核小版本升级,然后再升级插件版本。
使用示例
通过pg_repack --help
可以查看pg_repack的基本用法。
对全表(包括索引)进行repack的示例。
pg_repack --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --table schema1.table1
仅对索引进行repack的示例。
# --index 选项指定具体的索引名 $ pg_repack --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --index schema1.table1 # --only-indexes 选项指定该表的所有索引 $ pg_repack --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --table schema1.table1 --only-indexes
常见问题
Dry Run
正式执行pg_repack之前建议使用--dry-run
选项运行一次,该选项不操作表中的数据,仅验证命令是否合法、流程是否可以跑通。待命令验证成功后,再去掉该选项正式运行pg_repack。
$ pg_repack --dry-run --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --table schema1.table1
权限问题
必须使用高权限账号运行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
选项来绕过超级用户检查。
超时问题
如果需要repack的表或索引过大,repack过程耗时过长,则可能遇到FATAL: terminating connection due to idle-in-transaction timeout
、FATAL: terminating connection due to idle-session timeout
之类的错误。这表示pg_repack客户端与PolarDB PostgreSQL版集群的连接因为超时而断开,本次repack失败。
解决方法是在pg_repack命令之前增加PGOPTIONS
选项设置超时相关参数来关闭超时功能,以防止超时导致连接断开。
# PolarDB PostgreSQL 14:
$ PGOPTIONS="-c idle_session_timeout=0 -c idle_in_transaction_session_timeout=0 -c statement_timeout=0" pg_repack --no-superuser-check -h 连接串 -p 端口 -d database1 -U user --table schema1.table1
# PolarDB PostgreSQL 11:
$ PGOPTIONS="-c polar_idle_session_timeout=0 -c idle_in_transaction_session_timeout=0 -c statement_timeout=0" pg_repack --no-superuser-check -h 连接串 -p 端口 -d database1 -U user --table schema1.table1
异常退出清理
如果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
命令删除。
相关参考
pg_repack的更多信息可参考pg_repack官方帮助文档。
- 本页导读 (0)