《PostgreSQL技术内幕——原理探索》第六章 清理过程(VACUUM)

0    64    2

Tags:

👉 本文共约9511个字,系统预计阅读时间或需36分钟。

清理(VACUUM)是一种维护过程,有助于PostgreSQL的持久运行。它的两个主要任务是删除死元组,以及冻结事务标识,两者都在第5.10节中简要提到过。

为了移除死元组,清理过程有两种模式:并发清理(Concurrent Vacuum)完整清理(Full Vacuum) 。并发清理(通常简称为VACUUM)会删除表文件每个页面中的死元组,而其他事务可以在其运行时继续读取该表。相反,完整清理不仅会移除整个文件中所有的死元组,还会对整个文件中所有的活元组进行碎片整理。而其他事务在完整清理运行时无法访问该表。

尽管清理过程对PostgreSQL至关重要,但与其他功能相比,它的改进相对其他功能而言要慢一些。例如在8.0版本之前,清理过程必须手动执行(通过psql实用程序或使用cron守护进程)。直到2005年实现了autovacuum守护进程时,这一过程才实现了自动化。

由于清理过程涉及到全表扫描,因此该过程代价高昂。在版本8.4(2009)中引入了可见性映射(Visibility Map, VM)来提高移除死元组的效率。在版本9.6(2016)中增强了VM,从而改善了冻结过程的表现。

6.1节概述了并发清理的过程,而后续部分的内容如下所示:

  • 可见性映射
  • 冻结(Freeze)过程
  • 移除不必要的clog文件
  • 自动清理(AutoVacuum)守护进程
  • 完整清理

6.1 并发清理概述

清理过程为指定的表,或数据库中的所有表执行以下任务。

  1. 移除死元组

    • 移除每一页中的死元组,并对每一页内的活元组进行碎片整理。
    • 移除指向死元组的索引元组。
  2. 冻结旧的事务标识(

    • 如有必要,冻结旧元组的事务标识(txid)。
    • 更新与冻结事务标识相关的系统视图(pg_databasepg_class)。
    • 如果可能,移除非必需的提交日志(clog)。
  3. 其他

    • 更新已处理表的空闲空间映射(FSM)和可见性映射(VM)。
    • 更新一些统计信息(pg_stat_all_tables等)。

这里假设读者已经熟悉以下术语:死元组,冻结事务标识,FSM,clog;如果读者不熟悉这些术语的含义,请参阅第5章。VM将在第6.2节中介绍。

以下伪代码描述了清理的过程。

伪码:并发清理

  1. 从指定的表集中依次处理每一张表。
  2. 获取表上的ShareUpdateExclusiveLock锁, 此锁允许其他事务对该表进行读取。
  3. 扫描表中所有的页面,以获取所有的死元组,并在必要时冻结旧元组。
  4. 删除指向相应死元组的索引元组(如果存在)。
  5. 对表的每个页面执行步骤(6)和(7)中的操作
  6. 移除死元组,并重新分配页面中的活元组。
  7. 更新目标表对应的FSM与VM。
  8. 如果最后一个页面没有任何元组,则截断最后一页。
  9. 更新与目标表清理过程相关的统计数据和系统视图。
  10. 更新与清理过程相关的统计数据和系统视图。
  11. 如果可能,移除clog中非必需的文件与页面。

该伪码分为两大块:一块是依次处理表的循环,一块是后处理逻辑。而循环块又能分为三个部分,每一个部分都有各自的任务。接下来会描述这三个部分,以及后处理的逻辑。

6.1.1 第一部分

这一部分执行冻结处理,并删除指向死元组的索引元组。

首先,PostgreSQL扫描目标表以构建死元组列表,如果可能的话,还会冻结旧元组。该列表存储在本地内存中的maintenance_work_mem里(维护用的工作内存)。冻结处理将在第6.3节中介绍。

扫描完成后,PostgreSQL根据构建得到的死元组列表来删除索引元组。该过程在内部被称为“清除阶段(cleanup stage)”。不用说,该过程代价高昂。在10或更早版本中始终会执行清除阶段。在11或更高版本中,如果目标索引是B树,是否执行清除阶段由配置参数vacuum_cleanup_index_scale_factor决定。详细信息请参考此参数的说明

maintenance_work_mem已满,且未完成全部扫描时,PostgreSQL继续进行后续任务,即步骤4到7;完成后再重新返回步骤3并继续扫描。

6.1.2 第二部分

这一部分会移除死元组,并逐页更新FSM和VM。图6.1展示了一个例子:

图6.1 删除死元组

《PostgreSQL技术内幕——原理探索》第六章 清理过程(VACUUM) 假设该表包含三个页面,这里先关注0号页面(即第一个页面)。该页面包含三条元组, 其中Tuple_2是一条死元组,如图6.1(1)所示。在这里PostgreSQL移除了Tuple_2,并重排剩余元组来整理碎片空间,然后更新该页面的FSM和VM,如图6.1(2)所示。 PostgreSQL不断重复该过程直至最后一页。

请注意,非必需的行指针是不会被移除的,它们会在将来被重用。因为如果移除了行指针,就必须同时更新所有相关索引中的索引元组。

6.1.3 第三部分

第三部分会针对每个表,更新与清理过程相关的统计信息和系统视图。

此外,如果最后一页中没有元组,则该页会从表文件中被截断。

6.1.4 后续处理

当处理完成后,PostgreSQL会更新与清理过程相关的几个统计数据,以及相关的系统视图;如果可能的话,它还会移除部分非必需的clog(第6.4节)。

清理过程使用8.5节中将描述的环形缓冲区(ring buffer)。因此处理过的页面不会缓存在共享缓冲区中。

6.2 可见性映射

清理过程的代价高昂,因此PostgreSQL在8.4版中引入了VM,用于减小清理的开销。

本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信db_bao,谢谢!
《PostgreSQL技术内幕——原理探索》第六章 清理过程(VACUUM)后续精彩内容已被小麦苗无情隐藏,请输入验证码解锁本站所有文章!
验证码:
请先关注本站微信公众号,然后回复“验证码”,获取验证码。在微信里搜索“DB宝”或者“www_xmmup_com”或者微信扫描右侧二维码都可以关注本站微信公众号。

标签:

Avatar photo

小麦苗

学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

您可能还喜欢...

发表回复

嘿,我是小麦,需要帮助随时找我哦。
  • 18509239930
  • 个人微信

  • DB宝
  • 个人邮箱
  • 点击加入QQ群
  • 个人微店

  • 回到顶部