postgresql清理表空间(pg_repack)

RDS PostgreSQL支持用pg_repack插件在线清理表空间,解决表膨胀问题。介绍了使用该插件的前提条件、注意事项、功能、开启与关闭方法、客户端安装及使用示例,还给出常见问题的解决办法,如权限报错的处理。

RDS PostgreSQL支持通过插件pg_repack在线清理表空间,有效解决因对全表大量更新等操作引起的表膨胀问题。pg_repack无需获取排它锁,相比CLUSTER或VACUUM FULL更加轻量化。

前提条件

RDS实例需要满足以下条件:

实例大版本内核小版本
PostgreSQL 10、11、12或1320210331及以上
PostgreSQL 14或1520221030及以上

说明

查看和升级内核小版本,请参见升级内核小版本

注意事项

  • pg_repack需要额外的存储空间。全表repack时,剩余存储空间大小需要至少是待repack表大小的2倍。
  • pg_repack无法操作临时表。
  • pg_repack无法操作GiST索引。
  • pg_repack运行时无法对repack操作中的表执行DDL。pg_repack会持有ACCESS SHARE锁,禁止DDL执行。
  • 重建表和索引时会占用较多的磁盘IO,使用时请提前评估是否影响业务。以ESSD PL1云盘为例,repack 100GB的表时,会达到IO吞吐上限(250MB/s)。

功能介绍

pg_repack插件支持全表repack和索引repack。

  • 对整表数据进行repack的实现原理如下:
    1. 创建日志表记录对原表的变更。
    2. 在原表创建触发器,将原表的INSERT、UPDATE和DELETE操作记录到日志表中。
    3. 创建新表,与原表的行列相同。
    4. 在新表中创建索引。
    5. 将日志表里的变更应用到新表。
    6. 在system catalog交换新旧表。
    7. 删除旧表。

    说明

    pg_repack会在第a、b步和第f、g步短暂持有ACCESS EXCLUSIVE锁。其余步骤pg_repack只需要持有原表的ACCESS SHARE锁,不影响原表的INSERT、UPDATE和DELETE。

  • 对表中索引进行repack的实现原理如下:
    1. 以CONCURRENTLY方式创建新索引。
    2. 在system catalog交换新旧索引。
    3. 删除旧索引。

插件开启与关闭

说明

请使用高权限账号执行如下命令。

  • 开启插件。
    CREATE EXTENSION pg_repack;
  • 关闭插件。
    DROP EXTENSION pg_repack;

安装客户端

pg_repack插件需要配合客户端使用,以ECS Alibaba Cloud Linux 3.2104及以上版本为例,参考以下命令:

  1. 安装环境依赖。
    sudo yum install postgresql* redhat-rpm-config libpq* openssl-devel readline-devel -y
  2. 添加环境变量。
    export PATH=$PATH:/usr/lib64/pgsql/postgresql-12/bin
  3. 下载pg_repack客户端并编译安装。
    wget https://github.com/reorg/pg_repack/archive/refs/tags/ver_1.4.6.tar.gz
    tar zxvf ver_1.4.6.tar.gz
    cd pg_repack-ver_1.4.6
    make && make install

使用示例

-- 检查但不执行:--dry-run
pg_repack --dry-run --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --table schema1.table1

-- 检查并执行
pg_repack  --no-superuser-check --echo --no-order -h 连接串 -p 端口 -d database1 -U user --table schema1.table1

常见问题

Q:报错“ERROR: pg_repack failed with error: You must be a superuser to use pg_repack”。

A:请使用-k或--no-superuser-check,避免没有权限。

重要

全表repack时,无法通过此方式拥有权限。

摘自:如何在线清理RDS实例的表空间_云数据库 RDS-阿里云帮助中心

<think>我们遇到了死元组占比超过100%的情况,这通常是由于统计信息中n_live_tup(存活元组数)为0或非常小,而n_dead_tup(死元组数)不为0导致的。 在计算死元组占比时,我们使用了公式:$ \text{死元组占比} = \frac{\text{n\_dead\_tup}}{\text{n\_live\_tup}} \times 100 \% $。 当n_live_tup为0时,分母为0,但我们在计算中使用了GREATEST(n_live_tup, 1)来避免除0错误,此时如果n_dead_tup>0,那么占比就会超过100%。 可能的原因: 1. 表中有大量死元组,而存活元组数为0(例如表被清空后尚未被自动清理,或者表中有大量删除操作后没有插入新数据)。 2. 统计信息更新延迟,pg_stat_user_tables视图中的统计信息可能不是实时的。 解决方法: 1. 我们可以考虑当n_live_tup为0时,单独处理,比如将死元组占比显示为0(因为此时没有存活元组,死元组也没有实际影响)或者显示一个特殊值(例如'无穷大',但这样不直观)。 2. 更合理的做法是将死元组占比定义为:死元组数占(存活元组数+死元组数)的比例,即: $ \text{死元组占比} = \frac{\text{n\_dead\_tup}}{\text{n\_live\_tup} + \text{n\_dead\_tup}} \times 100 \% $ 修改后的SQL如下(同时调整状态判断逻辑): 注意:原状态判断逻辑使用的是死元组与存活元组的比值,现在我们改为死元组占总元组(存活+死亡)的比例。 修改后的查询语句: ```sql SELECT schemaname AS "模式名", relname AS "表名", pg_size_pretty(pg_total_relation_size(relid)) AS "总大小", pg_size_pretty(pg_relation_size(relid)) AS "数据大小", n_dead_tup AS "死元组数", -- 使用总元组数(存活+死亡)作为分母 ROUND((n_dead_tup::numeric * 100 / GREATEST(n_live_tup + n_dead_tup, 1)), 2) AS "死元组占比", CASE -- 当死元组占比超过20%时标记为需清理 WHEN (n_dead_tup::numeric * 100 / GREATEST(n_live_tup + n_dead_tup, 1)) > 20 THEN '需清理' -- 当超过10%时建议监控 WHEN (n_dead_tup::numeric * 100 / GREATEST(n_live_tup + n_dead_tup, 1)) > 10 THEN '建议监控' ELSE '正常' END AS "状态" FROM pg_stat_user_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema'); ``` 这样修改后,死元组占比永远不会超过100%,因为分子是分母的一部分(除非总元组数为0,此时分母为1,占比为0)。 另外,如果表的总元组数(存活+死亡)为0,那么分子也为0,所以计算结果为0。 说明:在PostgreSQL中,n_live_tup和n_dead_tup是统计信息,可能会在VACUUM和ANALYZE时更新。如果发现死元组占比很高,应该考虑手动执行VACUUM或调整自动清理参数。 自动清理相关设置可以参考[^1]。 如果死元组占比过高,除了手动执行VACUUM,还可以考虑使用VACUUM FULL(会锁表)或者pg_repack(在线重组工具,减少锁的影响)[^5]。 注意:在极端情况下,如果死元组非常多,VACUUM FULL或pg_repack可能是必要的,但要注意它们会占用较多资源。 参考文献: [^1]: 自动清理时间的设置 [^5]: 使用pg_repack在线重组表 相关问题: 1. 如何配置PostgreSQL的自动清理(autovacuum)参数? 2. 除了死元组占比,还有哪些指标可以判断表是否需要清理? 3. PostgreSQL中VACUUM FULL和pg_repack有什么区别? 下面我们将按照修改后的SQL语句进行查询,即可得到合理的死元组占比(0%~100%)。 </think>针对您遇到的死元组占比超过100%的问题,这通常是由于统计信息异常或特殊表状态导致的。以下是完整解决方案: ### 🔍 问题原因分析 1. **统计信息异常**: - 当 `n_live_tup`(存活元组)接近0时,$ \frac{\text{n\_dead\_tup}}{\text{n\_live\_tup}} $ 会无限放大 - 常见场景: - 表被大量删除后尚未清理 - 新创建但未初始化的表 - 系统统计信息更新延迟[^1] 2. **计算公式缺陷**: - 原公式 $ \text{死元组占比} = \frac{\text{n\_dead\_tup}}{\text{n\_live\_tup}} \times 100\% $ 分母可能为0或极小值 ### 🛠️ 解决方案:优化SQL查询 ```sql SELECT schemaname AS "模式名", relname AS "表名", pg_size_pretty(pg_total_relation_size(relid)) AS "总大小", pg_size_pretty(pg_relation_size(relid)) AS "数据大小", n_dead_tup AS "死元组数", -- 修正的死元组占比公式 CASE WHEN n_live_tup + n_dead_tup = 0 THEN 0.00 -- 空表处理 ELSE ROUND((n_dead_tup::numeric * 100 / (n_live_tup + n_dead_tup)), 2) END AS "死元组占比", -- 优化的状态判断逻辑 CASE WHEN n_live_tup + n_dead_tup = 0 THEN '空表' WHEN (n_dead_tup::numeric / (n_live_tup + n_dead_tup)) > 0.5 THEN '紧急清理' -- 阈值调整[^3] WHEN (n_dead_tup::numeric / (n_live_tup + n_dead_tup)) > 0.3 THEN '需清理' WHEN (n_dead_tup::numeric / (n_live_tup + n_dead_tup)) > 0.1 THEN '建议监控' ELSE '正常' END AS "状态" FROM pg_stat_user_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema'); ``` ### ✅ 关键改进 1. **数学公式修正**: - 使用 $ \text{死元组占比} = \frac{\text{n\_dead\_tup}}{\text{n\_live\_tup} + \text{n\_dead\_tup}} \times 100\% $ - 确保比值永远 ≤ 100%[^3] 2. **边界条件处理**: - 显式处理空表 (`n_live_tup + n_dead_tup = 0`) - 使用 `CASE` 避免除零错误 3. **阈值优化**: - 添加 `紧急清理` 状态(>50%) - 调整阈值基于行业最佳实践[^3] ### ⚙️ 后续处理建议 1. **紧急清理高占比表**: ```sql -- 单表清理 VACUUM FULL VERBOSE ANALYZE 模式名.表名; -- 批量清理占比>50%的表 DO $$ DECLARE tbl RECORD; BEGIN FOR tbl IN SELECT schemaname, relname FROM pg_stat_user_tables WHERE (n_dead_tup::numeric / GREATEST(n_live_tup + n_dead_tup, 1)) > 0.5 LOOP EXECUTE format('VACUUM FULL %I.%I', tbl.schemaname, tbl.relname); RAISE NOTICE '已清理表: %.%', tbl.schemaname, tbl.relname; END LOOP; END $$; ``` 2. **预防措施**: ```sql -- 调整自动清理参数 (postgresql.conf) autovacuum_vacuum_scale_factor = 0.05 -- 当死元组>5%时触发 autovacuum_vacuum_cost_delay = 10ms -- 降低清理延迟 -- 对大表单独配置 ALTER TABLE 表名 SET ( autovacuum_vacuum_scale_factor = 0.02, autovacuum_analyze_scale_factor = 0.01 ); ``` 3. **使用在线重组工具**(避免锁表): ```bash # 安装pg_repack pg_repack --table 模式名.表名 -k # 保持原表在线[^5] ``` ### 📊 监控建议 1. 创建定期监控视图: ```sql CREATE VIEW dead_tup_monitor AS SELECT /* 上述优化后的SQL */; ``` 2. 配置告警规则(死元组占比 > 30%持续1小时) --- ### 相关问题 1. PostgreSQL自动清理无法及时处理高更新表怎么办? 2. 使用`pg_repack`重组表时如何最小化业务影响?[^5] 3. 除了死元组占比,还有哪些表健康指标需要监控?[^2] 4. 如何区分正常死元组和统计信息异常的情况?[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值