PostgreSQL的MVCC(多版本并发控制)机制和表膨胀的解决方法

结论:PG数据库导致表膨胀的原因是逻辑删除的历史数据清除不及时

表及索引的膨胀
主流的MVCC机制如下:
1、以Oracle和Innodb为例,写如新数据时,把旧数据转移到一个单独的地方,如回滚段中,如果其他人读取数据时,从回滚段中把数据读取出来,可以有效避免膨胀。
2、以SQL Server为代表的,把旧版本的的数据写入专门的临时表空间中,新数据写入日志中,然后去更改数据,也可以有效地避免膨胀。
3、PG修改时,旧数据不删除,只是标注为无效(逻辑删除,在某个时间再去清理)

Oracle和Innodb的undo实现形式:
Oracle最经典的错误就是回滚段快照过旧,意思是回滚段中的数据还在被某些事务使用,但是数据在回滚段中已经被删除了,Innodb也有这样的问题。
如果在一个超大事务执行过程中,事务失败了,它会回滚,产生大量cpu和IO占用(因为要从undo segment回滚段,导入data segment中)。

PG的优点
1、无论进行多少操作,事务回滚都会立即完成(秒级回滚),Oracle使用了回滚段,如果Oracle宕机时很多事务正在运行,再次启动后,需要把之前的事务回滚(具体的一会儿再说),当没有回滚完成时数据行上仍然有锁,业务不能正常操作,如果需要回滚的业务量很大,情况会很坏。
2、可以放心执行超大事务不必像Oracle和Innodb那样需要经常保证回滚段不会被用完,也不用像Oracle那样会遇到ORA-1555错误的困扰。
PG的缺点:
1、旧版本数据需要清理,在8.3版本引入了autovacuum,采用多进程架构,支持多表的同时操作。
2、旧版本的数据清理不及时会导致性能下降
3、空间持续上涨,存储没有得到有效的利用

原因:
表及索引膨胀是指随着时间推移,表和索引的物理存储结构逐渐变得不连续或者产生空洞导致数据库性能下降的问题。这种情况通常由以下几个原因引起:
1、更新和删除操作频繁(vacuum会清理它留下来的历史版本):
当表中的行经常被更新或删除时,PostgreSQL 的MVCC(多版本并发控制)机制(历史数据回收不及时)可能会导致数据页面的分裂和空洞的产生。例如,当更新或删除一行后,原来的数据页可能留下了空洞或者变得不再紧凑
2、自动化的 VACUUM 过程不足够频繁:
PostgreSQL 使用 VACUUM 进程来回收被删除行所占用的空间,并且重新组织数据以减少表和索引的膨胀。如果 VACUUM 过程不足够频繁,或者数据库负载很高,可能会导致表和索引的膨胀问题积累。
3、长时间运行的事务:
长时间运行的事务可以阻碍 VACUUM 进程的正常工作,从而使得表和索引无法及时进行空间的回收和重新组织。
4、未正确设置和优化参数:
PostgreSQL 的参数设置(如 autovacuum 相关参数、vacuum_cost_delay、maintenance_work_mem 等)可能影响 VACUUM 进程的执行效率和频率,进而影响表和索引的膨胀问题的处理。
解决方法:
定期监控数据库的性能指标,如表和索引的空间利用率,以及 VACUUM 进程的运行情况。根据监控结果调整数据库配置和优化策略。

常见问题及处理流程

表膨胀查询SQL(安装表膨胀系数倒叙排序)
 SELECT
  current_database() AS db, schemaname, tablename, 
  ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat,
  CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
  CASE WHEN relpages < otta THEN
    CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
    ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
      ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
  END AS totalwastedbytes
FROM (
  SELECT
    nn.nspname AS schemaname,
    cc.relname AS tablename,
    COALESCE(cc.reltuples,0) AS reltuples,
    COALESCE(cc.relpages,0) AS relpages,
    COALESCE(bs,0) AS bs,
    COALESCE(CEIL((cc.reltuples*((datahdr+ma-
      (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值