为什么会有表膨胀及表膨胀的危害
为什么会有表膨胀
从原理来说:
pg旧数据存储在数据文件中,并不立刻清理,只是标记为无效。这些旧数据如果不能及时清理,业务表和数据文件会越来越大,引发表膨胀。
从具体场景来说:哪些情况会导致旧数据不能及时清理
未开启autovacuum或者禁用了track_counts参数
autovacuum过慢(例如IO问题、触发阈值不合理、执行周期不合理、配置了延迟触发,worker过于忙碌等)
大事务或者DML量过大,产生死元组速度快于清理
长事务,包括pg_dump和pg_dumpall,默认会以可重复读级别开启事务
慢查询(包括增删改查和DDL)
游标未关闭
复制槽 + hot_standby_feedback + 备库大查询,会导致主库可以vacuum的xmin很小
表膨胀的危害
表和数据文件占用空间持续增长
查询表时要扫描的数据块可能增多,查询速度变慢
需要用vacuum full处理(如果不用其他插件),vacuum full会获取表的8级锁,阻塞对表的所有操作,影响业务。并且最大会占有原来磁盘空间的两倍,可能打爆磁盘空间。
对应前面具体场景,如何避免表膨胀
开启autovacuum,启用track_counts参数
保证autovacuum性能:
将数据库迁移至高性能存储
合理的触发阈值(autovacuum_vacuum_threshold和autovacuum_vacuum_scale_factor)
合理的执行周期 autovacuum_naptime
性能足够时,关闭延迟设置 autovacuum_vacuum_cost_delay
合理的工作进程数和内存(autovacuum_max_workers和autovacuum_work_mem)
应用程序设计时,尽量避免如下:
过于频繁的DML操作
慢SQL(包括增删改查和DDL在内的所有的SQL)
大事务、长事务
打开游标后不关闭
在不必要的场景使用已提交读以上隔离级别
对大库执行pg_dump进行逻辑备份(隐式repeatable read隔离级别的全库备份)
设置idle_in_transaction_session_timeout,控制长事务的存活时间
设置old_snapshot_threshold参数,强制删除为过老的事务快照保留的dead元组(这会导致长事务读取已被删除的tuple时出错)。
对于大表,建议使用分区,可以加快vacuum的速度
如何处理表膨胀
vacuum full,cluster
重建表(手动,或者pg_reorg,pg_repack)
评论
有用 1
墨值悬赏

