PostgreSQL VACUUM 没有效果(无法清理死元组)的原因

众所周知,在PostgreSQL里面使用VACUUM FULL来回收dead tuples空间并将其返回给操作系统。但是我执行VACUUM FULL却没有任何效果,是数据库版本出现了bug?当然不是!
经排查原来是Physical Replication Slot导致(具体解释见http://mysql.taobao.org/monthly/2015/02/03/)。将hot_standby_feedback设为on时,从库关闭,主库的xmin不再改变,主库的vaccum操作停滞,造成主库被频繁更新的表大小暴增。

为什么VACUUM不清理死元组

VACUUM只能删除不再需要的那些行版本(也称为“元组”)。如果删除事务的事务 ID(存储在xmax中)早于 PostgreSQL 数据库(或共享表的整个集群)中仍处于活动状态的最旧事务,则无法清除元组

在 PostgreSQL 集群中,有三件事可以阻止这个VACUUM回收死元组:

  1. 长时间运行的事务:

    可以通过以下查询找到长时间运行的事务及其xmin值:

    SELECT pid, datname, usename, state, backend_xmin
    FROM pg_stat_activity
    WHERE backend_xmin IS NOT NULL
    ORDER BY age(backend_xmin) DESC;

    可以使用该pg_terminate_backend()函数来终止阻止您的VACUUM.

  2. 废弃的Replication Slot:

    复制槽是一种数据结构,保持从主库丢弃但仍需要由备用服务器赶上主要信息PostgreSQL服务器的数据。

    如果复制延迟或备用服务器关闭,复制槽将阻止VACUUM删除旧行。

    可以使用此查询找到所有复制槽及其xmin值:

    SELECT slot_name, slot_type, database, xmin
    FROM pg_replication_slots
    ORDER BY age(xmin) DESC;

    使用该pg_drop_replication_slot()函数删除不再需要的复制槽。

    注意:如果hot_standby_feedback = on对于逻辑复制存在类似的危险(无法回收元组),但只有系统目录受到影响。catalog_xmin在这种情况下检查列

  3. 孤立的准备运行的事务:

    两阶段提交期间,分布式事务首先用PREPARE语句准备,然后用COMMIT PREPARED语句提交

    一旦一个事务准备好,它就会一直“等待”直到它被提交或中止。它甚至必须在服务器重启后还需要保留下来!通常,事务不会长时间保持准备状态,但有时会出错,必须由管理员手动删除准备好的事务。

    可以xmin使用以下查询找到所有准备好的交易及其价值:

    SELECT gid, prepared, owner, database, transaction AS xmin
    FROM pg_prepared_xacts
    ORDER BY age(transaction) DESC;

    使用ROLLBACK PREPAREDSQL 语句删除准备好的事务。

 

posted @   VicLW  阅读(2322)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2019-10-11 (译)内存沉思:多个名称相关的神秘的SQL Server内存消耗者。
2019-10-11 SQLServer中重建聚集索引之后会影响到非聚集索引的索引碎片吗
2019-10-11 Sql Server 内存相关计数器以及内存压力诊断
2019-10-11 SQL Server 数据库启动过程(用户数据库加载过程的疑难杂症)
点击右上角即可分享
微信分享提示

目录导航