先来看一例公有云服务登录web页面端卡住案例:
故障现象:WEB端登录非常缓慢,需要耗时5~10分钟才能登录,登录成功之后,就不卡了;
排查过程:网络正常,服务器资源正常,数据库层发现慢SQL
一条简单的查询select 居然耗时了150s
故障原因:根据慢SQL定位到功能点是Web端在登录时权限校验用户组织权限表t_pm_user引起的缓慢,查询该表数据量很小,只有1600行,查询表大小,发现表居然有4GB左右;表膨胀率达1526倍。
表中死元组过多,现在就明确了问题就是该表膨胀导致的。经过了解业务发现:客户配置了每小时一次人员增量同步,每次同步都update表,由于同步频率高,导致表膨胀厉害。
解决办法:
vacuum full 表并设置该表的回收阈值,并反馈研发优化这个功能点
表膨胀是指表的数据和索引所占文件系统的空间,在有效数据量并未发生大的变化的情况下,不断增大。表膨胀不仅浪费了大量的磁盘空间,甚至某些查询场景下,导致表扫描耗时长,影响查询语句效率。就如上述例子中的表t_pm_user,仅有1600多行数据,但是表对应的物理文件已经4GB。
PG数据库的表膨胀是基于MVCC的存储机制:



普通的vacuum会做大概如下几件事情:
可以看到,普通的vacuum只是清理死元组,"腾出"空间,在今后有新数据插入时,将优先使用该空间,直到所有被重用的空间用完时,再考虑新增页面。

如上图所示,普通vacuum只是标记了dead tuple,并未重组页面,导致上图3个页面使用率特别低,每个页面仅存放1个tuple,而且在某些情况下,每个页面的空闲空间又不是固定大小的,所以如果要利用这些空间空间,就需要遍历一遍数据页面来找到它们,这样会造成比较大的I/O开销,表膨胀越大,开销就越大。
因此,PG就引入vacuum full这个操作,vacuum full会对表进行重组,也就意味着表的oid会变,所以不能我们在日常操作中,因此它需要lock table,而且要定位表的oid的时候,不能通过pg_class的oid来找,得通过pg_class的relfilenode来找,这样才精确。而且,vacuum full最大会占据原来磁盘空间的两倍,所以请预留好磁盘空间。

既然已经了解了PG的膨胀原理,PG数据库也引入了autovacuum,为什么还是会有膨胀表存在呢?有以下几种可能性导致膨胀表不能被清理:
步骤1:获取膨胀表及膨胀索引数据
使用上面这2个视图可以获取当前数据库里的膨胀表及索引情况;可以根据膨胀率进行筛查,及时处理优化膨胀表。
步骤2:处理表膨胀
常用手段:
ALTER TABLE t SET (autovacuum_vacuum_threshold = 1000);
ALTER TABLE t SET (autovacuum_vacuum_scale_factor = 0.1);--表大小的缩放系数;
ALTER TABLE t SET (autovacuum_vacuum_cost_limit = 1000);---对 vacuum 执行 cost 进行评估,限制在1000,超过就延迟;
ALTER TABLE t SET (autovacuum_vacuum_cost_delay = 10);--延迟的时间即为10ms
手动vacuum full 表
根据上一步骤找出来的膨胀表,在非业务时段进行vacuum full tablename; 此操作需要lock table,8级别锁,针对特别大的表,评估是否需要做此类操作。对于大表,建议使用分区,可以加快vacuum的速度。
膨胀索引在线重建
在比较繁忙的系统或者大表上执行该语句的话,可以使用concurrently 参数:
create index concurrently idx_table_name_x1 on table_name(col_name);
插件处理
pg_repack
pg_sequeeze
优化应用程序设计
应用程序设计时,尽量避免如下: