背景

不知道从何时开始,数据库空载时的性能消耗越来越高,当业务高峰期,CPU 和内存都处于高负载的情况下,观看 AWS 的监控,发现负载空载时占用很高。

并且占用较高的 Top5 分为为:

autovacuum: VACUUM ANALYZE pg_catalog.pg_attribute
autovacuum: VACUUM ANALYZE pg_catalog.pg_type
autovacuum: VACUUM ANALYZE pg_catalog.pg_depend
autovacuum: VACUUM ANALYZE pg_catalog.pg_class
autovacuum: VACUUM ANALYZE pg_catalog.pg_index

由上面的 Top5 可以得知,目前数据库的负载较高,都是由于 PgSql 系统表的 VACUUM 导致的,但是,为什么会出现这种情况呢?我们一起来慢慢解决这个问题吧!

问题排查

排查方向

VACUUM 是 PgSql 的一种垃圾回收机制,主要用于清理数据库中的不再需要的行(也称为“死亡行”或“dead tuples”),并且它回收这些行占用的空间。VACUUM操作还更新数据库的统计信息,这对于查询优化器来说非常重要。

如果 VACUUM 太慢,则有可能有以下几个原因:

  • 大容量数据:如果数据库非常大,VACUUM操作可能需要很长时间来完成,这会增加系统负载。
  • 高事务量:在高事务量的系统中,频繁的更新、插入和删除操作会产生许多不再需要的行,导致VACUUM工作量增加。
  • 不频繁的清理:如果长时间没有运行VACUUM,会导致数据库中积累大量的死亡行,需要更长时间来清理。

因为当前数据库集群都处于业务的低谷期,所以基本上没有啥负载,所以高事务量 可以排除,而数据库一直在频繁的执行清理任务,所以问题基本上可以锁定到大容量数据!

谁占用了空间?

因此,我们首先从数据表的空间占用上面进行问题排查!

我们可以使用 [[维护相关#数据表统计#数据表空间占用大小 | 数据表空间占用大小统计]] 相关 SQL:

SELECT
relname,
PG_SIZE_PRETTY(PG_TOTAL_RELATION_SIZE(oid)) AS total_size,
PG_SIZE_PRETTY(PG_RELATION_SIZE(oid)) AS relation_size,
*
FROM
pg_class
WHERE
relname LIKE 'pg_%'
AND relname NOT LIKE 'pg_toast_%'
ORDER BY
PG_TOTAL_RELATION_SIZE(oid) DESC
LIMIT 100
;

下面是返回的结果信息:

relname total_size relation_size
pg_attribute 32 GB 23 GB
pg_attribute_relid_attnam_index 5615 MB 5613 MB
pg_class 4303 MB 2877 MB
pg_attribute_relid_attnum_index 3595 MB 3594 MB
pg_depend 3584 MB 1616 MB
pg_type 3030 MB 2092 MB

上面 pg_attribute 总大小(数据表+索引)为:32 GB,因此,基本上可以判断,数据库的负载变高,是由于 pg_attribute 系统表导致的!

pg_attribute

那么问题来了,pg_attribute 到时候是什么数据表呢?

以下是 AI 助手 Kimi 给出的解答:

在PostgreSQL数据库中,pg_attribute是一个系统目录表,它存储了关于表列的信息。每个表的列都有相应的行记录在这个表中,包括系统表和用户定义的表。

pg_attribute表是PostgreSQL中众多系统目录表之一,它们为数据库中的各种对象提供了元数据。通过查询这些系统表,你可以获得关于数据库结构和配置的详细信息。

简而言之,它是一张 pgsql 的元数据信息表,存储 pg 数据库中的各个表字段的定义信息。

理论上,一个数据库中的数据表即使再多,它的元数据信息也不可能超过 30 GB,因此,我们接下来的排查方向,是要找出为什么 pg_attribute 数据表这么大!

数据膨胀

在我将此问题在网络上进行搜索的时候,一个新的名词出现在我的眼前:数据膨胀

PostgreSQL 数据膨胀是指数据库中的数据文件大小超出了实际存储数据所需的大小。这可能会导致存储空间的浪费,并且可能影响数据库的性能。以下是一些可能导致 PostgreSQL 数据膨胀的原因以及相应的解决方法:

  • 索引膨胀

    • 原因:随着数据的更新和删除,索引可能会变得“膨胀”,特别是对于B树索引。
    • 解决方法:定期重建索引可以减少膨胀。可以使用REINDEX命令来实现。
  • 表膨胀
    • 原因:表中的数据更新和删除操作可能导致表变得碎片化,从而增加表的物理大小。
    • 解决方法:使用VACUUM FULL命令来压缩表并回收空间。但请注意,这将创建一个新的表并重置统计信息。
  • 长事务
    • 原因:长时间运行的事务会锁定行,导致VACUUM不能回收空间。
    • 解决方法:避免长时间运行的事务,或者使用事务 ID 来限制事务的持续时间。
  • 未及时清理删除的数据
      • 原因:删除数据后,如果VACUUM没有运行,那么空间不会被回收。
    • 解决方法:定期运行VACUUM(或使用autovacuum)来清理不再需要的行。
  • 系统表膨胀
    • 原因:系统表,如pg_attribute,可能会因为存储了大量的元数据而变得庞大。
    • 解决方法:审查系统表的使用,移除不必要的元数据。

通过对上面造成数据膨胀的原因进行排查,最后锁定了最重要的两条:

  • 重复创建临时表:公司的很多业务涉及到 批量更新 ,为了使批量更新的速度更快,因此使用了 临时表方案 方案,重复执行 CREATE TEMP TABLE AS SELECT * FROM TABLE ,导致 pg_attribute 的数据一直处于上升的阶段。
  • 长事务:数据库的数据需要实时同步至数据仓库,同步是采用的 Flink-CDC 实时同步至 StarRocks,Flink-CDC 在同步阶段,会默认打开一个复制槽,当复制槽的 WAL 日志未被订阅者消费的时候,会存在一个长事务!

问题源头

下面,我来进行一个复盘,来说明为什么 pg_attribute 为什么会发生数据膨胀!

业务系统时时刻刻在执行 CREATE TEMP TABLE 命令,因此 pg_attribute 的数据会频繁的进行数据的插入和删除,正常情况下,及时 PgSql 的 VACUUM 会自动将删除的数据从磁盘中移除。

但是,因为数据库的数据需要同步至 数据仓库 ,因此使用了 Flink-CDC 进行同步,Flink-CDC 会开启一个复制槽,正常运行的情况下, Flink-CDC 会实时消费复制槽中的 WAL 日志,如果 Flink-CDC 同步任务关闭,但是又未关闭复制槽,复制槽为了保证订阅者数据完整性,会自动记录 FLink-CDC 上一次消费的位置,方便 Flink-CDC 下一次重启,重新监听 WAL 日志。

为了保证 WAL 日志的完整性,因此 PgSql 需要开启一个长事务,防止 PgSql 数据库的 VACUUM 把数据从磁盘清除。

所以,pg_attribute 数据表的数据因为长事务的原因,一直未被 VACUUM,所以导致数据表一直处于膨胀阶段,而因为 pg_attribute 是系统表,假如执行 VACUUM FULL pg_attribute ,将会锁全库,因此即使当后续事务关闭了,pg_attribute 的空间也无法得到正常的释放!

解决方案

停止创建临时表

因为系统一直在创建临时表,所以系统一直在对 pg_attribute 表进行 VACUUM ,假如 pg_attribute 的数据不再更新,那么就不会触发数据库的 VACUUM 了!

此方法治标不治本,只是避免了频繁执行 vacuum pg_attribute,从而减小系统负载

执行 VACUUM FULL

执行 vacuum full pg_attribute,但是此方案会锁全库,因此执行的时候,必须停服执行,对业务的影响较大。

PGSQL数据膨胀问题排查的更多相关文章

  1. 以elasticsearch-hadoop 向elasticsearch 导数,丢失数据的问题排查

    实际这是很久之前的问题了,当时没时间记录 这里简单回顾 项目基于 数据架构不方便说太细,最精简的 somedata-> [kafka]->spark-stream->elastics ...

  2. 数据库char varchar nchar nvarchar,编码Unicode,UTF8,GBK等,Sql语句中文前为什么加N(一次线上数据存储乱码排查)

    背景 公司有一个数据处理线,上面的数据经过不同环境处理,然后上线到正式库.其中一个环节需要将数据进行处理然后导入到另外一个库(Sql Server).这个处理的程序是老大用python写的,处理完后进 ...

  3. InnerJoin分页导致的数据重复问题排查

    2016年8月9号美好的七夕的早上,我精神抖擞地来到公司.一会之后,客服宅宅MM微信我,说一个VIP大店铺订单导出报表中一个订单有重复行.于是,我赶紧开始查探问题所在.经过一天的反复仔细追查(当然还包 ...

  4. 【Spark调优】数据倾斜及排查

    [数据倾斜及调优概述] 大数据分布式计算中一个常见的棘手问题——数据倾斜: 在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或j ...

  5. Hive数据导入HBase引起数据膨胀引发的思考

    最近朋友公司在做一些数据的迁移,主要是将一些Hive处理之后的热数据导入到HBase中,但是遇到了一个很奇怪的问题:同样的数据到了HBase中,所占空间竟增长了好几倍!详谈中,笔者建议朋友至少从几点原 ...

  6. Mysql 和 Postgresql(PGSQL) 对比

    Mysql 和 Postgresql(PGSQL) 对比 转载自:http://www.oschina.net/question/96003_13994 PostgreSQL与MySQL比较 MySQ ...

  7. Redis性能问题排查解决手册(七)

     阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_commands_processed 延迟时间 内存碎片率 回收key 总结 性能相关的数据指标 通过Red ...

  8. Redis性能问题排查解决手册

    转自:http://www.cnblogs.com/mushroom/p/4738170.html 阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_comma ...

  9. Spark性能优化之道——解决Spark数据倾斜(Data Skew)的N种姿势

    原创文章,同步首发自作者个人博客转载请务必在文章开头处注明出处. 摘要 本文结合实例详细阐明了Spark数据倾斜的几种场景以及对应的解决方案,包括避免数据源倾斜,调整并行度,使用自定义Partitio ...

  10. 干货!一次kafka卡顿事故排查过程

    由于一次功能上线后,导致某数据量急剧下滑,给我们紧张的呢!排查过程也是个学习过程(这其中有大部分是领导们的功劳,不过分享给大家应该也不犯法吧,ᐓ) 1. 确认问题的真实性? 被数据部门告知,某数据量下 ...

随机推荐

  1. Java 注解使用教程

    简介 Java 1.5 引入了注解,现在它在 Java EE 框架(如 Hibernate.Jersey 和 Spring )中被大量使用.Java 注释是该语言的一个强大特性,用于向 Java 代码 ...

  2. 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案

    今天在使用国产数据库金仓时,我发现每次遇到问题都习惯性地打开金仓社区进行搜索和查看相关信息.可是每次打开浏览器的操作总让我觉得有些麻烦,于是我决定不再依赖这种繁琐的过程.索性今天我把这个接口提取出来, ...

  3. 关于#pragma comment的小认识

    #pragma 指令 #pragma为预处理指令,作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主 ...

  4. Longest Univalue Path——LeetCode进阶路

    原题链接https://leetcode.com/problems/longest-univalue-path 题目描述 Given a binary tree, find the length of ...

  5. 使用SimpleDateFormat获取指定时区时间

    摘要:使用SimpleDateFormat把时间戳转换成指定格式的.指定时区的字符串.   SimpleDateFormat是Java中的一个日期格式化类,继承了DateFormat,可以实现日期时间 ...

  6. Java面试题:浅谈Spring Bean的生命周期

    摘要:如果熟悉Spring 中 Bean的生命周期,可以加深对Spring的认知,故综述一下Bean的生命周期. 前言   Spring中Bean的生命周期是找工作的时候会被问到的高频面试题,主要用于 ...

  7. Re:prime 关于质数的算法

    Re:prime 关于质数的所有算法 绪言 所有代码若无说明,均采用快读模板 关于质数,无非就两大类: 判断一个数字是不是质数 找出[1,n]中所有的质数 先讲1: Judge 判断x是不是质数 根据 ...

  8. java里面的高精度运算

    1 package com.lv.study.am.first; 2 3 import java.math.BigDecimal; 4 5 public class TestBigDecimal { ...

  9. ChatMoney是你创业自由副业的plan B!

    本文由 ChatMoney团队出品 人生永远要有Plan B,在当下的市场经济环境中,工作收入和日常支出完全不能平衡,导致生活质量越来越不理想.如果觉得实在撑不下去,也许可以换个思路.我在工作之余,也 ...

  10. AI应用实战课学习总结(3)预测带货销售额

    大家好,我是Edison. 最近入坑黄佳老师的<AI应用实战课>,记录下我的学习之旅,也算是总结回顾. 今天是我们的第3站,了解下AI项目实践的5大环节,并通过一个预测直播带货销售额的案例 ...