PostgresSql VACUUM 剖析
为什么需要 Vacuum
MVCC
MVCC:Multi-Version Concurrency Control,即多版本并发控制。
PostgreSQL 使用多版本并发控制(MVCC)来支持高并发的事务处理,同时保持数据的一致性和隔离性。MVCC 是一种用于管理数据库并发操作的技术,它允许多个事务同时访问同一数据,而不会产生冲突或阻塞。
MVCC 的工作原理
版本化:
PostgreSQL 为表中的每行数据存储多个版本。当一个事务更新一行数据时,它不会立即覆盖原始数据,而是创建该数据的新版本。
事务ID:
每个事务被分配一个唯一的事务ID(XID),该ID 用于跟踪数据的变更。快照:
当一个事务开始时,它会创建一个快照,该快照是数据库在某一时刻的状态。即使其他事务在该事务进行时对数据进行了更改,该事务仍然可以看到它开始时的数据库状态。可见性规则:
MVCC 通过一组可见性规则来确定事务可以看到哪些数据版本。通常,一个事务只能看到在它开始之前已经提交的其他事务所做的更改。垃圾回收:
PostgreSQL 使用VACUUM 命令来清理不再需要的数据版本,释放空间。VACUUM 操作由系统自动调度,也可以手动执行。
MVCC 的关键特点:
- 无锁读取:
MVCC 允许其他事务在读取数据时不被锁定,因为它们可以访问数据的旧版本。 - 写入时复制:
当数据被更新时,PostgreSQL 会复制旧版本的数据并创建新版本,而不是直接在原地修改。 - 隔离级别:
PostgreSQL 支持不同的事务隔离级别,如读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。隔离级别决定了事务可以看到其他事务更改的时间点。 - 性能:
MVCC 可以提高数据库的性能,因为它减少了锁的争用和事务间的阻塞。 - 一致性:
通过使用快照,MVCC 确保了事务在整个过程中看到的是一致性的数据视图。
MVCC 的挑战:
- 表膨胀:
由于多版本的存在,表可能会膨胀,需要定期维护。 - 长事务:
长事务可能导致较旧的数据版本长时间不被回收,从而影响性能和空间。 - 系统资源:
MVCC 需要额外的系统资源来管理多个数据版本。
MVCC 是 PostgreSQL 强大并发控制机制的核心,它使得数据库能够高效地处理大量的并发事务,同时保持数据的一致性和隔离性。
表膨胀
多版本并发控制机制(MVCC)的原理在于,当它需要更改某块数据的时候,它不会直接去更改,而是会创建这份数据的新版本,在新版本进行更改,所以会存储多份版本,每个事务能看见哪一份版本的数据,由事务隔离级别控制。
MVCC引入了一个问题,如何消除老旧的、没有使用的无用数据(版本),目前主流上有3种处理实现方式:
来看看各种数据库的解决方式:
以Oracle为代表的,把旧版本数据放入UNDO,新数据放入REDO,然后更改数据。这种方式,旧版本的数据放入了UNDO,所以可以有效避免膨胀。
以SQL Server为代表的,把旧版本的数据写入专门的临时表空间,新数据写入日志,然后去更改数据。这种方式,旧版本的数据放入了专门的临时表空间,所以也可以有效地避免膨胀。
以PostgreSQL为代表的,把旧版本标示为无效,新数据写入日志,成功后把新版本的数据写入新的位置。这种实现机制是导致数据膨胀严重的一个重要原因,因为旧版本的数据虽然表示为无效状态,但是没被回收前还是占据存储空间。
Vacuum 工作原理
PostgreSQL的表膨胀清理就需要依赖vacuum,vacuum的主要任务就是清理表和索引中不需要的数据(dead tuples),为新加入的数据清理出来空间。
Vacuum
PostgreSQL中的VACUUM命令是一种数据库维护任务,用于清理数据库中的无用空间(也称为“dead tuples”或“ghost tuples”),并防止表膨胀。VACUUM还更新数据库的统计信息,这些信息由查询优化器用来选择最有效的查询计划。以下是VACUUM如何工作的详细步骤:
- 标记删除:
PostgreSQL使用一种称为标记-清除(mark-sweep)的垃圾收集机制。当DELETE或UPDATE命令删除或修改表中的数据行时,原始数据行不会被立即从存储中移除,而是被标记为“已删除”。这意味着这些行仍然占用空间,但对查询来说是不可见的。 - 移除元组:
这里的移除dead tuples只是标记为可重用该空间,并没有真正物理删除。所以vacuum清理表后,表的实际空间并没有减小。dead tuples在做移除标记后,vacuum会重新排列剩余的元组以进行碎片化整理。然后,需要更新目标表的VM(可见性映射文件)和FSM(空闲空间映射文件)。 - 更新统计信息:
VACUUM收集有关表和索引中数据分布的统计信息,并将这些信息存储在系统目录中。这些统计信息对于查询优化器来说是至关重要的,因为它们帮助优化器决定如何执行查询。
VACUUM在这段时间删除的数据,并不会从此磁盘上删除,只是将数据标为可删除,这部分可删除的空间会出现以下两种情况:
- 当有新的数据进行,新数据会写入至这部分可删除的空间中,即老数据从磁盘上移除了
- 系统执行
vacuum full ,PgSql 会重新整理所有的元组(Tuples),最终将数据从磁盘上移除,这一步比较耗费资源和时间,有可能锁表,生产环境慎用!
Vacuum Full
Vacuum Full和Vacuum最大的不同就是,Vacuum Full是物理删除dead tuples,并把释放的空间重新交给操作系统,所以在vacuum full后,表的大小会减小为实际的空间大小。其处理过程和 vacuum 大不相同,处理步骤如下:
创建排它锁
vacuum full 开始执行时,系统会先对目标创建一个AccessExclusiveLock ,不允许外界再进行访问(为后面拷贝做准备)。
创建新表
系统会创建一张表结构和源表一模一样的新表,方便后续做数据操作。
复制数据
扫描目标表,把表中的live tuples 拷贝到新表中。
替换数据表
删除目标表,在新表上,重新创建索引,更新VM, FSM以及统计信息,相关系统表等。
综上所述,vacuum full的本质是生成一个新的数据文件,然后把原有表的live tuples存放到该数据文件中。对比vacuum, vacuum full缺点就是在执行期间不能对表进行访问,由于需要往新表中导入live tuples数据,其执行效率也会很慢。优点是执行后,表空间只存放live tuples,没有冗余的dead tuples,在执行查询效率上会有所提高。
但是,vacuum full 也有存在的问题,在执行过程中,它会block所有对表的访问,不只是写操作,读操作也会全部block。很多情况下这是不可接受的,尤其是生产环境。
Vacuum 的好处
PostgreSQL中的VACUUM命令具有多个好处,主要包括:
- 回收空间:
VACUUM可以清理数据库中的无用空间,即那些被标记为“已删除”的行占用的空间,从而释放这些空间供其他数据使用。 - 更新统计信息:
VACUUM会更新数据库的统计信息,这些信息对于查询优化器选择最有效的查询计划至关重要。 - 维护索引:
VACUUM还会维护索引,删除索引中指向已删除数据行的条目,并可能重建索引以优化性能。 - 防止表膨胀:随着时间推移,表中的死元组会越来越多,这会导致存储空间利用率下降,
VACUUM可以防止这种情况。 - 提高查询性能:通过清理无用的元组,
VACUUM可以减少查询需要遍历的数据量,从而提高查询性能。 - 自动回收空间:
VACUUM可以自动回收已经释放的空闲空间,减少了数据库管理员的手动干预。
VACUUM是PostgreSQL数据库维护和性能优化的重要组成部分,正确理解和运用VACUUM命令及其变种,对于保持数据库的良好运行状态具有重要意义。
Vacuum 的最佳实践
PostgreSQL中的VACUUM操作是数据库维护的重要组成部分,以下是一些最佳实践:
- 定期执行VACUUM:根据业务负载和表的更新频率,制定合理的VACUUM策略,特别是对于频繁更新的大表。
- 启用并调优Autovacuum:依赖Autovacuum来自动维护数据库健康。通过调整
autovacuum_vacuum_threshold和autovacuum_vacuum_scale_factor等参数,可以更精确地控制自动VACUUM的触发时机。 - 考虑使用VACUUM FULL:虽然
VACUUM FULL可以最大程度地释放磁盘空间,但由于它可能会锁定表并需要较长时间执行,建议在业务低峰期使用,并确保有足够的磁盘空间来创建表的新副本。 - 监控Vacuum活动:利用
pg_stat_user_tables视图或其他监控工具,了解Vacuum操作的状态和效果,以便及时调整相关参数。 - 不要无故运行手动VACUUM或ANALYZE:Autovacuum通常可以很好地管理数据库,除非有特殊情况,否则不必频繁手动执行这些操作。
- 在数据批量加载后运行ANALYZE:在大量新数据被插入数据库后,运行ANALYZE以确保统计信息的准确性,从而帮助查询优化器制定更有效的查询计划。
- 收集数据库信息:在调整参数或实施手动VACUUM/ANALYZE之前,收集有关数据库的足够信息,如表的行数、死元组数、最后一次VACUUM/ANALYZE的时间等,以便做出更明智的决策。
通过遵循这些最佳实践,可以确保数据库的性能和健康状况得到良好的维护。
参考文档:
PostgreSQL的表膨胀与Vacuum和Vacuum Full - 明矾 - 博客园
深入浅出 PostgreSQL VACUUM 流程,全面掌控数据健康与性能! - ByteZoneX社区
blog/202405/20240530_01.md at master · digoal/blog · GitHub
PostgresSql VACUUM 剖析的更多相关文章
- 通过源码安装PostgresSQL
通过源码安装PostgresSQL 1.1 下载源码包环境: Centos6.8 64位 yum -y install bison flex readline-devel zlib-devel yum ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
- [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute
剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...
- Membership三步曲之进阶篇 - 深入剖析Provider Model
Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...
- 《AngularJS深度剖析与最佳实践》简介
由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...
- 探索c#之Async、Await剖析
阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
- [C#] 走进异步编程的世界 - 剖析异步方法(上)
走进异步编程的世界 - 剖析异步方法(上) 序 这是上篇<走进异步编程的世界 - 开始接触 async/await 异步编程>(入门)的第二章内容,主要是与大家共同深入探讨下异步方法. 本 ...
- [C#] 走进异步编程的世界 - 剖析异步方法(下)
走进异步编程的世界 - 剖析异步方法(下) 序 感谢大家的支持,这是昨天发布<走进异步编程的世界 - 剖析异步方法(上)>的补充篇. 目录 异常处理 在调用方法中同步等待任务 在异步方法中 ...
随机推荐
- 解决更新WIFI驱动后出现网络适配器黄色三角警告
更新WIFI驱动后出现网络适配器黄色三角警告问题的解决方案 在更新 Intel 无线网卡驱动后,遇到了网络适配器异常的问题,尤其是在曾经安装/卸载过 VMware 的电脑上.本篇文章将详细介绍这个问题 ...
- Vue知识沉淀
为什么组件my-item的props是listCount,但传入时候用:list-count传入,而 listCount与list-count不一致 <!DOCTYPE html> < ...
- ES查不到最近的数据解决方法
其实是因为索引的刷新策略导致的,不是实时刷新的. 下载开源的 ES 界面客户端ES King:https://github.com/Bronya0/ES-King 连接后,选择索引,选择flush索引 ...
- Kali Linux 从入门到实战:系统详解与工具指南
Kali Linux 从入门到实战:系统详解与工具指南 1. Kali Linux 简介 Kali Linux 是一款基于 Debian 的 Linux 发行版,专为 渗透测试 和 网络安全审计 设计 ...
- CountDownLatch和FutureTask类使用方法解析
摘要:使用CountDownLatch和FutureTask解决主线程需要拿到多个子线程任务的执行结果之后再进行执行的问题. 综述 我们在工作中,经常遇到有些业务场景需要使用多线程异步执行任务,从 ...
- git reset回滚未提交的更改和覆盖分支
摘要:介绍git reset使用技巧:回滚本地所有未提交的更改,用一个分支覆盖另一个分支. git回滚本地所有未提交的更改可以使用命令 git reset,它的功能是强制覆盖本地文件到指定分支.切 ...
- 20244104陈思淼 《Python程序设计》实验三报告
课程:<Python程序设计> 班级:2441 姓名:陈思淼 学号:20244104 实验教师:王志强 实验日期:20254月20日 必修/选修: 公选课 1.实验内容 创建服务端和客户端 ...
- 工程师都喜欢的一款自动生成网格的仿真软件——Hyperworks到底好不好用?
HyperWorks是一款广泛应用于工程仿真和优化的软件平台,其中包括了许多强大的工具和功能.其中的网格自动生成工具是其重要组成部分之一,对于工程仿真和优化来说具有重要的意义.那么,HyperWork ...
- Fortran77教程
Fortran77 教程
- 最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈
2025原创研发flutter3+dart3实战仿微信App聊天系统Flutter3Chat. flutter3_wechat:基于最新跨平台框架flutter3.32+dart3.8+get_sto ...