文档

pg_repack

更新时间:

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的实现原理如下:

    1. 创建日志表,记录repack期间对原表的变更。

    2. 在原表上创建触发器,将原表的INSERTUPDATEDELETE操作记录到日志表中。

    3. 创建原表结构相同的新表并将原表数据导入其中。

    4. 在新表中创建与原表相同的索引。

    5. 将日志表里的变更应用到新表。

    6. 在系统catalog交换新旧表。

    7. 删除旧表。

    说明
    • pg_repack会在第1、2、6、7步短暂持有原表的ACCESS EXCLUSIVE锁。其余步骤pg_repack只需要持有原表的ACCESS SHARE锁,不阻塞对原表的INSERTUPDATEDELETE操作,但会阻塞DDL操作。

    • pg_repack需要额外的存储空间来保存新表和日志表,因此剩余存储空间大小需要至少是被repack表大小的两倍。

    • 对带有Global Index的表进行repack操作会有较长时间持有排它锁并阻塞DML,不建议对这种表进行repack操作。

    • 不支持对临时表进行repack操作。

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

    1. CONCURRENTLY方式创建新索引。

    2. 在系统catalog交换新旧索引。

    3. 删除旧索引。

      说明
      • 如果索引空闲空间过多,推荐采用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 timeoutFATAL: 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)
文档反馈