PostgreSQL的表膨胀及对策

本文涉及的产品
PolarSearch,搜索节点 4核8GB
PolarDB Agent Flow,2核4GB
PolarDB Agent Express,2核4GB
简介: PostgreSQL的表膨胀及对策 PostgreSQL的MVCC机制在数据更新时会产生dead元组,这些dead元组通过后台的autovacuum进程清理。

PostgreSQL的表膨胀及对策

PostgreSQL的MVCC机制在数据更新时会产生dead元组,这些dead元组通过后台的autovacuum进程清理。一般情况下autovacuum可以工作的不错,但以下情况下,dead元组可能会不断堆积,形成表膨胀(包括索引膨胀)。

  1. autovacuum清理速度赶不上dead元组产生速度
  2. 由于以下因素导致dead元组无法被回收
    • 主库或备库存在长事务
    • 主库或备库存在未处理的未决事务
    • 主库或备库存在断开的复制槽

检查表膨胀

方法1:查询pg_stat_all_tables系统表

SELECT
    schemaname||'.'||relname,
    n_dead_tup,
    n_live_tup,
    round(n_dead_tup * 100 / (n_live_tup + n_dead_tup),2) AS dead_tup_ratio
FROM
    pg_stat_all_tables
WHERE
    n_dead_tup >= 10000
ORDER BY dead_tup_ratio DESC
LIMIT 10; 

方法2:使用pg_bloat_check工具

`pg_bloat_check`会进行全表扫描,比`pg_stat_all_tables`准确,但比较慢对系统性能冲击也较大,不建议作为常规工具使用。 

以上方法包含了对索引膨胀的检查。但需要注意的是,表中不能被回收的dead tuple在索引页里是作为正常tuple而不是dead tuple记录的。考虑到这一点,索引的实际膨胀要乘以对应表的膨胀率。

预防表膨胀

  1. 调整autovacuum相关参数,加快垃圾回收速度

    对于写入频繁的系统,默认的autovacuum_vacuum_cost_limit参数值可能过小,尤其在SSD机器上,可以适当调大。

    autovacuum_vacuum_cost_limit = 4000 
  2. 监视并处理以下可能导致dead元组无法被回收的状况

    • 长事务
    • 未决事务
    • 断开的复制槽
  3. 强制回收

    设置old_snapshot_threshold参数,强制删除为过老的事务快照保留的dead元组。这会导致长事务读取已被删除tuple时出错。

    old_snapshot_threshold = 12h 

    old_snapshot_threshold不会影响更新事务和隔离级别为RR只读事务。old_snapshot_threshold参数也不能在线修改,如果已经设置了old_snapshot_threshold但又需要运行更长的RR只读事务或单个大的只读SQL,可以临时在备机上设置max_standby_streaming_delay = -1,然后在备机执行长事务(会带来主备延迟)。

  4. 杀死长事务

    设置可以部分避免长事务的参数

    idle_in_transaction_session_timeout = 60s
    lock_timeout = 70s 

相关代码

vacuum()
  ->vacuum_rel()
      ->vacuum_set_xid_limits()
          ->GetOldestXmin()
              找出以下最小的事务ID,大于该事务ID的事务删除的tuple将不回收
              - backend_xid,所有后端进程的当前事务ID的最小值
              - backend_xmin,所有后端进程的事务启动时的事务快照中最小事务的最小值
              - replication_slot_xmin,所有复制槽中最小的xmin(备库的backend_xid和backend_xmin会在这里反映)
              - replication_slot_catalog_xmin,所有复制槽中最小的catalog_xmin
          ->TransactionIdLimitedForOldSnapshots()
                如果设置了old_snapshot_threshold,则比backend_xid和old_snapshot_threshold->xmin都老的dead元组也可以被回收 

参考

-PostgreSQL 9.6 快照过旧 - 源码浅析

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
SQL 关系型数据库 PostgreSQL
把PostgreSQL的表导入SQLite
把PostgreSQL的表导入SQLite
492 0
|
SQL 关系型数据库 数据库
postgresql中连接两张表更新第三张表(updata)
如何结合两张表的数据来更新第三张表
873 0
|
SQL 监控 关系型数据库
实时计算 Flink版操作报错合集之在设置监控PostgreSQL数据库时,将wal_level设置为logical,出现一些表更新和删除操作报错,怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
关系型数据库 PostgreSQL
postgresql如何将没有关联关系的两张表的字段合并
【6月更文挑战第2天】postgresql如何将没有关联关系的两张表的字段合并
526 3
|
关系型数据库 PostgreSQL
postgresql将没有关联关系的两张表合并成一张
【5月更文挑战第4天】postgresql将没有关联关系的两张表合并成一张
680 5
|
SQL 关系型数据库 数据库连接
ClickHouse(20)ClickHouse集成PostgreSQL表引擎详细解析
ClickHouse的PostgreSQL引擎允许直接查询和插入远程PostgreSQL服务器的数据。`CREATE TABLE`语句示例展示了如何定义这样的表,包括服务器信息和权限。查询在只读事务中执行,简单筛选在PostgreSQL端处理,复杂操作在ClickHouse端完成。`INSERT`通过`COPY`命令在PostgreSQL事务中进行。注意,数组类型的处理和Nullable列的行为。示例展示了如何从PostgreSQL到ClickHouse同步数据。一系列的文章详细解释了ClickHouse的各种特性和表引擎。
772 0
|
SQL 关系型数据库 PostgreSQL
【sql】PostgreSQL物化视图表使用案例
【sql】PostgreSQL物化视图表使用案例
259 0
|
关系型数据库 PostgreSQL
postgresql如何将没有关联关系的两张表合并成一张
【6月更文挑战第2天】postgresql如何将没有关联关系的两张表合并成一张
469 0
|
关系型数据库 数据库 PostgreSQL
postgresql | 数据库| 生成2000W条的简单测试表
postgresql | 数据库| 生成2000W条的简单测试表
557 0
|
关系型数据库 PostgreSQL
PostgreSQL表用户列最大个数
PostgreSQL表用户列最大个数
776 0

推荐镜像

更多