关于postgresql:PostgresqlVACUUM-垃圾回收

34次阅读

共计 19875 个字符,预计需要花费 50 分钟才能阅读完成。

#Postgersql

介绍

原始英文文档:PostgreSQL: Documentation: 15: VACUUM

对应的中文文档:VACUUM (postgres.cn),根本都是机翻倡议对照学习不会迷茫。

官网只用了一句话介绍 VACUUM:

garbage-collect and optionally analyze a database

VACUUM 能够认为手动触发 Postgresql 垃圾回收的原始命令,须要留神查阅的文档版本为:PostgreSql 14

比 VACUUM 更为重要的是 AUTO_VACUUM,放到本文最初探讨,当然 VACUUM 是底层实现。

为什么叫 VACUUM?

介绍干燥的文档内容之前,集体先猜想一波起名垃圾回收为 VACUUM 的起因:

  1. 因为 VACUUM 机制失常参数下只会把死元组的空间重用,不会把申请的空间归还给操作系统,所以相似抽真空的感觉。
  2. 如果是 VACUUM FULL,此时会把空间重用并且把空间还给操作系统,这时候的抽真空又像是把一块空间整个“剥离”进来。

当然以上纯属集体瞎扯,也有可能是这个名字对于开发者来说会感觉很COOL

相干语法

VACUUM [( _`option`_ [, ...] ) ] [_`table_and_columns`_ [, ...] ]
VACUUM [FULL] [FREEZE] [VERBOSE] [ANALYZE] [_`table_and_columns`_ [, ...] ]

where _`option`_ can be one of:

    FULL [_`boolean`_]
    FREEZE [_`boolean`_]
    VERBOSE [_`boolean`_]
    ANALYZE [_`boolean`_]
    DISABLE_PAGE_SKIPPING [_`boolean`_]
    SKIP_LOCKED [_`boolean`_]
    INDEX_CLEANUP {AUTO | ON | OFF}
    PROCESS_TOAST [_`boolean`_]
    TRUNCATE [_`boolean`_]
    PARALLEL _`integer`_

and _`table_and_columns`_ is:

    _`table_name`_ [( _`column_name`_ [, ...] ) ]

留神这种圆括号的用法是官网举荐的,如果要批改参数,就须要用圆括号否则会报错无奈通过。

作用

既然是回收垃圾过程,那么要回收什么货色? 其实很简略,清理 死元组,这里依据文档一一剖析

清理死元组

VACUUM reclaims storage occupied by dead tuples,这里说 Postgresql 回收的是死元组,元组是 Postgresql 数据结构的根本组成单位,比拟像 Mysql 的数据页。

那么死元组是怎么来的呢?上面就有一句很要害的话:

tuples that are deleted or obsoleted by an update are not physically removed from their table

好家伙假更新和假删除是吧,也就是说删除是在元组进行标记,而更新则能够认为是先标记删除而后“插入”,是不是感觉十分相熟?

接下来一句话也比拟要害:

they remain present until a VACUUM is done

VACUUM执行完垃圾回收之后才会把死元组进行回收。这时候垃圾回收的执行频率和垃圾回收过程执行自身就十分要害了,这里接着往下看:

Without a _table_and_columns_ list, VACUUM processes every table and materialized view in the current database that the current user has permission to vacuum. With a list, VACUUM processes only those table(s).

在没有 table_and_columns 列表的状况下,VACUUM 会解决 以后用户具备清理权限 的,以后数据库中的每一个表和物化视图。(然而理论用的时候大部分状况须要超级用户或者具备较高权限的系统管理员,个别用户是没有这个权限的)

table_and_columns 是啥?
指的是垃圾回收能够指定表以及列,如果不想对所有表做清理,在手动清理的时候能够进行配置。

此外 Postgresql 针对垃圾回收开发了另一个子命令 VACUUM ANALYZE,能够通过此命令对于运行的 Postgresql 实例进行剖析,也是实现主动垃圾回收的要害组件之一。

这里不过多探讨 ANALYZE,咱们能够间接看看成果:
命令:VACUUM VERBOSE ANALYZE(VERBOSE 示意显示剖析进度和详细信息)
0 pages are entirely empty.

CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO:  vacuuming "pg_toast.pg_toast_88998"
INFO:  index "pg_toast_88998_index" now contains 0 row versions in 1 pages
DETAIL:  0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO:  "pg_toast_88998": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 3643386
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO:  analyzing "public.xxxxxx"
INFO:  "xxxxxx": scanned 837 of 837 pages, containing 11930 live rows and 0 dead rows; 11930 rows in sample, 11930 estimated total rows

OK
查问工夫: 11.3s

膨胀

膨胀是因为设计自身附带的益处,这里简略介绍不作为钻研重点。膨胀更偏差于 VACUUM FULL,因为它波及磁盘 IO 操作,在清理掉过期索引的同时,为接下来的数据流入预调配新的空间进行存储,同时清理掉过期索引能够实现死元组空间复用,缩小磁盘空间的占用节约。

咱们简略并且疾速理解 VACUUM 的作用,接着持续依据文档理解更多细节。

参数介绍

集体依据官网文档摘录了局部参数重要的阐明同时做了一张表,不用记忆只须要简略理解而后实战的时候回来回顾查阅即可。

Option english description 中文解释
FULL Selects“full”vacuum, which can reclaim more space, but takes much longer and exclusively locks the table 能够回收更多空间,然而会锁表并且回收工夫会变长
PROCESS_TOAST Specifies that VACUUM should attempt to process the corresponding TOAST table for each relation, if one exists. 指定 VACUUM 应该尝试为每个关系解决相应的 TOAST 表(如果存在的话)。默认是开启状态。
个人观点:通常不倡议批改此参数
INDEX_CLEANUP VACUUM will skip index vacuuming when there are very few dead tuples in the table.
The default is AUTO.
If INDEX_CLEANUP is set to ON, VACUUM will conservatively remove all dead tuples from indexes. This may be useful for backwards compatibility with earlier releases of PostgreSQL where this was the standard behavior.
If INDEX_CLEANUP is set to ON, VACUUM will conservatively remove all dead tuples from indexes.
INDEX_CLEANUP can also be set to OFF to force VACUUM to always skip index vacuuming, even when there are many dead tuples in the table.
通常状况下表中死元组比拟少会跳过索引扫描。
默认设置为 AUTO。
如果设置为 ON:则每次清理都会扫描索引,反之如果为 OFF,则所有的清理动作都会跳过索引扫描
FREEZE Selects aggressive“freezing”of tuples. Specifying FREEZE is equivalent to performing VACUUM with the vacuum_freeze_min_age and vacuum_freeze_table_age parameters set to zero
option is redundant when FULL is specified
此选项示意会激进解冻元组,指定此参数相当于执行 VACUUM 的同时把并将 vacuum_freeze_min_age 和 vacuum_freeze_table_age 参数设置为 0。
如果是 VACUUM FULL 此选项有效
ANALYZE Updates statistics used by the planner to determine the most efficient way to execute a query. 应用此参数能够立刻刷新分析器的剖析后果,对于某些场景的调优很有帮忙。
VERBOSE Prints a detailed vacuum activity report for each table. 打印垃圾回收的详细信息,察看垃圾回收的具体情况
DISABLE_PAGE_SKIPPING Normally, VACUUM will skip pages based on the visibility map.
This option disables all page-skipping behavior, and is intended to be used only when the contents of the visibility map are suspect, which should happen only if there is a hardware or software issue causing database corruption.
看介绍根本是一个无关痛痒的参数,应用此选项会启动敞开跳页。通常只有在数据库呈现重大问题的状况下此参数才有应用价值
SKIP_LOCKED Specifies that should not wait for any conflicting locks to be released when beginning work on a relation: if a relation cannot be locked immediately without waiting, the relation is skipped
Also, while ordinarily processes all partitions of specified partitioned tables, this option will cause to skip all partitions if there is a conflicting lock on the partitioned table.VACUUMVACUUMVACUUM ANALYZEVACUUMVACUUM
指定在开始解决关系时不应期待开释任何抵触锁。如果 无奈在不期待的状况下立刻锁定关系,则跳过该关系
尽管通常会解决指定分区表的所有分区,然而如果分区表上有抵触的锁,这个选项会导致跳过所有分区。
TRUNCATE Specifies that VACUUM should attempt to truncate off any empty pages at the end of the table and allow the disk space for the truncated pages to be returned to the operating system. 指定 VACUUM 应该尝试截断表末的任何空页,并容许将截断页的磁盘空间返回给操作系统。这通常是所心愿的行为,也是默认的。
个人观点:通常不倡议批改此参数
PARALLEL(13 版本之后失效) Perform index vacuum and index cleanup phases of VACUUM in parallel using integer background workers (for the details of each vacuum phase, please refer to Table 28.39)
vacuum which is limited by the number of workers specified with PARALLEL option if any which is further limited by max_parallel_maintenance_workers
An index can participate in parallel vacuum if and only if the size of the index is more than min_parallel_index_scan_size.
Only one worker can be used per index.
These behaviors might change in a future release. This option can’t be used with the FULL option.
应用指定的线程数在后盾工作器并行地执行 VACUUM 的索引真空和索引清理阶段。
如果有 PARALLEL 选项的话,真空会受到 PARALLEL 选项所指定的工作器数量的限度,而这又受到 max_parallel_maintenance_workers 的限度。
当且仅当一个索引的大小超过 min_parallel_index_scan_size 时,该索引能力参加并行真空。
每个索引只能用独自工作器工作。意味着不保障理论执行的时候须要用到指定数量的工作器。
这个参数的工作机制将来有可能会发生变化,并且这个选项 不能 和 FULL 一起用。

接着介绍一些无关紧要的参数:

  • boolean:能够是 true、1,选项如果不做指定默认为 true
  • integer:PARALLEL 指定并行处理器的数量,必须是非负整数。
  • table_name:反对指定表的垃圾回收。
  • column_name:反对指定列的垃圾回收。

PARALLEL

特意拿出来说一下,这个参数官网在 Postgresql 13 版本才退出,个人感觉是受到 Mysql 的“刺激”退出的,作用是指定垃圾回收线程的 并发数 ,用户能够手动指定非零值进行指定,当然这个值不是自在指定的,官网存在对应的“ 最大值”限度胡乱传参。

select version()

如果想要理解不同的线程并发数对于理论利用的影响比照,能够看看这篇英文文章的参数实际介绍:

Parallelism comes to VACUUM – 2ndQuadrant | PostgreSQL

集体筛选了相干论断局部:

I’ve evaluated the performance of parallel vacuum on my laptop (Core i7 2.6GHz, 16GB RAM, 512GB SSD). The table size is 6GB and has eight 3GB indexes. The total relation is 30GB, which doesn’t fit the machine RAM. For each evaluation, I made several percent of the table dirty evenly after vacuuming, then performed vacuum while changing the parallel degree. The graph below shows the vacuum execution time.
我曾经评估了笔记本电脑(Core i7 2.6GHz,16GB RAM,512GB SSD)上的 (多 CPU) 并行 vacuum 的性能。Table 大小为 6GB,有八个 3GB Index。Related 为 30GB,不适宜机器 RAM。对于每次评估,我在垃圾回收后平均地制作百分之几的脏元组(类比脏数据页),而后在扭转并行度的同时进行 vacuum。下图显示了 vacuum 执行工夫。

Result:
In all evaluations the execution time of the index vacuum accounted for more than 95% of the total execution time.
显然如果设置的 CPU 并行数量适合,能够大幅度的缩小垃圾回收的执行工夫。减小 Postgresql 抖动状况呈现。

FREEZE

在文档中提到了 FREEZE 参数,说实话不晓得官网文档在说啥,集体理解目前还不够深刻,先翻译放着留个坑,有须要实战或者试验的时候再深入研究:

Translation:
vacuum_freeze_min_age(VACUUM 解冻最小年龄):Specifies the cutoff age (in transactions) that VACUUM should use to decide whether to freeze row versions while scanning a table. The default is 50 million transactions
指定 VACUUM 用来决定是否在扫描表时解冻行版本的 截止年龄 (以事务为单位)。默认值是 5000 万个事务。
vacuum_freeze_table_age(触发解冻年龄):VACUUM performs an aggressive scan if the table’s pg_class.relfrozenxid field has reached the age specified by this setting. The default is 150 million transactions
如果表的 pg_class.relfrozenxid 字段 达到 这个设置所指定的年龄,VACUUM 会执行 踊跃的扫描。默认值是 1.5 亿个记录。

细节

VACCUM 清理阶段介绍

英文文档形容

Phase Description
initializing VACUUM is preparing to begin scanning the heap. This phase is expected to be very brief.
scanning heap VACUUM is currently scanning the heap. It will prune and defragment each page if required, and possibly perform freezing activity. The heap_blks_scanned column can be used to monitor the progress of the scan.
vacuuming indexes VACUUM is currently vacuuming the indexes. If a table has any indexes, this will happen at least once per vacuum, after the heap has been completely scanned. It may happen multiple times per vacuum if maintenance_work_mem (or, in the case of autovacuum, autovacuum_work_mem if set) is insufficient to store the number of dead tuples found.
vacuuming heap VACUUM is currently vacuuming the heap. Vacuuming the heap is distinct from scanning the heap, and occurs after each instance of vacuuming indexes. If heap_blks_scanned is less than heap_blks_total, the system will return to scanning the heap after this phase is completed; otherwise, it will begin cleaning up indexes after this phase is completed.
cleaning up indexes VACUUM is currently cleaning up indexes. This occurs after the heap has been completely scanned and all vacuuming of the indexes and the heap has been completed.
truncating heap VACUUM is currently truncating the heap so as to return empty pages at the end of the relation to the operating system. This occurs after cleaning up indexes.
performing final cleanup VACUUM is performing final cleanup. During this phase, VACUUM will vacuum the free space map, update statistics in pg_class, and report statistics to the statistics collector. When this phase is completed, VACUUM will end.

中文文档对应的形容,倡议凑合着看:

阶段 形容
初始化 VACUUM正在筹备开始扫描堆。这个阶段很简短。
扫描堆 VACUUM正在扫描堆。如果须要,它将会对每个页面进行建筑以及碎片整顿,并且可能会执行解冻动作。heap_blks_scanned列能够用来监控扫描的进度。
清理索引 VACUUM以后正在清理索引。如果一个表领有索引,那么每次清理时这个阶段会在堆扫描实现后至多产生一次。如果 maintenance_work_mem 不足以寄存找到的死亡元组,则每次清理时会屡次清理索引。
清理堆 VACUUM以后正在清理堆。清理堆与扫描堆不是同一个概念,清理堆产生在每一次清理索引的实例之后。如果 heap_blks_scanned 小于heap_blks_total,零碎将在这个阶段实现之后回去扫描堆;否则,零碎将在这个阶段实现后开始清理索引。
革除索引 VACUUM以后正在革除索引。这个阶段产生在堆被齐全扫描并且对堆和索引的所有清理都曾经实现当前。
截断堆 VACUUM正在截断堆,以便把关系尾部的空页面返还给操作系统。这个阶段产生在革除完索引之后。
执行最初的革除 VACUUM在执行最终的革除。在这个阶段中,VACUUM将清理闲暇空间映射、更新 pg_class 中的统计信息并且将统计信息报告给统计收集器。当这个阶段实现时,VACUUM也就完结了。

无 FULL 条件回收

Plain VACUUM (without FULL) simply reclaims space and makes it available for re-use, This form of the command can operate in parallel with normal reading and writing of the table, as an exclusive lock is not obtained

通常状况下没有 FULL 参数的回收仅仅把那些标记为死元组的空间进行复用。留神整个垃圾回收的操作是没有任何锁操作的,所以能够和用户线程 并行,这就意味着紧急问题能够根本没有副作用的疾速进行此操作。

集体补充:尽管官网说这个回收很强并且根本能够无副作用运行,然而仍然不倡议对整个库这样干,该当先对于以后 Postgresql 的数据各个表的健康状况剖析而后定位对应的表和列进行清理,其次是 VACUUM FULL 要给表加独占锁,代价很大不能在负载高的时候手动调用。

论断:不倡议或者禁止对于全库做 VACUUM 和 VACUUM FULL,哪怕官网解释能够和用户过程并行。

无 FULL 条件回收会导致这些额定的空间 不能归还给操作系统 重新分配,也就是说空间还是被占用了,只不过外面的空间期待重用而已。

extra space is not returned to the operating system (in most cases);

官网把这种回收形式叫做 parallel vacuum

应该如何禁用?

要禁用 Vacuum 性能,能够应用 PARALLEL 选项并将并行工作程序指定为零。相似上面的写法,这样就不会产生任何工作器进垃圾回收动作。

强调 PARALLEL 0 这种用法是 13 才开始呈现,集体尝试的时候公司的版本刚好是 12 就间接模仿命令了。

VACUUM(PARALLEL 0)

有 FULL 条件回收

其实大抵区别也能够猜出来,VACUUM FULL会将表的整个内容重写到一个 新的磁盘文件 中,然而因为存在物理磁盘 IO 所以开销比拟大,并且清理过程须要加一个表级的排他锁,此时 其余用户线程无奈进行读写

而与之绝对的 VACUUM FULL 的益处是不蕴含额定的空间,这使得没有被应用的空间被 还给操作系统

注意事项

  1. 执行垃圾回收的操作的用户必须领有相干表的权限。
  2. VACUUM 只容许非事务执行
  3. 对具备 GIN 索引的表,VACUUM(任何模式)也会通过将待处理索引项挪动到次要 GIN 索引构造中的适合地位,来实现任何待处理的索引插入。
  4. 倡议常常清理生产数据库(至多每晚在零碎低沉闷量的时候执行一次),以保障移除生效的行。比拟套路的计划是定时工作,这里就不过多探讨了。
  5. 日常应用时,不举荐 FULL 选项 ,但在非凡状况时它会有用。举个例子是当你删除或者更新了一个表中的 绝大部分 行时,如果你心愿在 物理上膨胀表以缩小磁盘空间占用 并且容许更快的表扫描,则该选项是比拟适合的。
  6. PARALLEL选项管制并行启动的垃圾回收线程数量。如果此选项与 ANALYZE 选项一起指定,则 不会影响ANALYZE
  7. VACUUM会导致 I / O 流量的大幅度减少,这可能导致数据其余过程流动受到影响。(波及底层数据结构的变动)。
  8. 有时倡议应用 基于代价的清理提早个性。这一个点放到下文补充阐明。
  9. 对于并行清理,倡议依照探讨设置为 CPU 的外围数量成果最优,此外不倡议并行数量超过 CPU 外围数量。
  10. PostgreSQL 包含了“autovacuum”守护过程,它能够主动进行例行的清理保护表。然而留神垃圾回收过程的优先级很低,只在必要的时候进去工作,这和很多高级编程语言有相似之处。
  11. 每个运行 VACUUM 但没有 FULL 选项的后端将在 pg_stat_progress_vacuum 视图中报告其进度。运行 VACUUM FULL 的后端将在 pg_stat_progress_cluster 视图中报告它们的进度。

补充

基于老本的 VACUUM 提早

During the execution of VACUUM and ANALYZE commands, the system maintains an internal counter that keeps track of the estimated cost of the various I/O operations that are performed.

The intent of this feature is to allow administrators to reduce the I/O impact of these commands on concurrent database activity.

This feature is disabled by default for manually issued commands. To enable it, set the variable to a nonzero value .VACUUM`vacuum_cost_delay`

在执行 VACUUM 和 ANALYZE 命令期间,系统维护一个外部计数器,用于跟踪所执行的各种 I/O 操作的预计老本。此性能的目标是容许管理员缩小这些命令对并发数据库流动的 I/O 影响。默认状况下,对于手动收回的命令,此性能处于禁用状态,默认状况下,对于手动收回的命令,此性能处于禁用状态.

vacuum_cost_delay (floating point)

The amount of time that the process will sleep when the cost limit has been exceeded.

当超过老本限度时,过程将休眠的工夫量。(默认值是零)

vacuum_cost_page_hit (integer)

The estimated cost for vacuuming a buffer found in the shared buffer cache.

对共享缓冲区缓存中发现的缓冲区进行 vacuuming 的预计老本。

vacuum_cost_page_miss (integer)

The estimated cost for vacuuming a buffer that has to be read from disk.

对一个必须从磁盘上读取到缓冲区进行 vacuuming 的预估老本

vacuum_cost_page_dirty (integer)

The estimated cost charged when vacuum modifies a block that was previously clean.

当 vacuum 批改一个之前是污浊的块时所须要的的预估老本

vacuum_cost_limit (integer)

The accumulated cost that will cause the vacuuming process to sleep. The default value is 200.

默认为 200,指的是导致 VACUUM 休眠的累计老本。

pg_stat_all_tables(重要)

简略来讲这个表存储了以后所有表的“衰弱状态”,不过比拟纳闷的是官网没有在 VACUUM 文档页面援用这个表的相干内容,集体收集一些文章才得悉这个强的离谱的表,真的是十分坑。

pg_stat_all_tables 表展现了以后零碎内所有数据表的衰弱状态,通过此表能够查看以后某个表被索引扫描次数,插入记录条数,被删除记录条数,更新记录条数等,是一个十分用助于线上问题排查的表(奈何藏得不起眼而且层级也藏得比拟深)。

这里不一一介绍参数了,间接给一个 SQL 和具体成果更加直观:

SELECT
    relname 表名,
    seq_scan 全表扫描次数,
    seq_tup_read 全表扫描记录数,
    idx_scan 索引扫描次数,
    idx_tup_fetch 索引扫描记录数,
    n_tup_ins 插入的条数,
    n_tup_upd 更新的条数,
    n_tup_del 删除的条数,
    n_tup_hot_upd 热更新条数,
    n_live_tup 流动元组估计数,
    n_dead_tup 死亡元组估计数,
     last_vacuum 最初一次手动清理工夫,
    last_autovacuum 最初一次主动清理工夫,
    last_analyze 最初一次手动剖析工夫,
    last_autoanalyze 最初一次主动剖析工夫,
    vacuum_count 手动清理的次数,
    autovacuum_count 主动清理的次数,
     analyze_count 手动剖析此表的次数,
    autoanalyze_count 主动剖析此表的次数,
    (CASE WHEN n_live_tup > 0 THEN n_dead_tup :: float8 / n_live_tup :: float8 ELSE 0 END) :: NUMERIC (12, 2) AS "死 / 活元组的比例"
FROM
    pg_stat_all_tables
WHERE
    schemaname = 'public'
ORDER BY n_dead_tup::float8 DESC;

pg_stat_progress_cluster

Progress for VACUUM FULL commands is reported via pg_stat_progress_cluster because both VACUUM FULL and CLUSTER rewrite the table

VACUUM FULL 命令的进度是通过 pg_stat_progress_cluster 报告的,因为 VACUUM FULL 和 CLUSTER 命令都会重写表。

所以咱们能够通过 pg_stat_progress_cluster 表查看以后的垃圾回收进度报告。如果咱们在执行垃圾回收的时候开启日志参数,也是查问这张表的相干数据进行展现。

这里就不一个个翻译了,对于凋谢人员来说实战的时候对这个表查一下数据长什么样根本就分明是干啥的,印象也会更深(没错我就是懒)。

Table 28.40. pg_stat_progress_vacuum View

对应原文链接:PostgreSQL: Documentation: 15: 28.4. Progress Reporting

Column TypeDescription
pid integerProcess ID of backend.
datid oidOID of the database to which this backend is connected.
datname nameName of the database to which this backend is connected.
relid oidOID of the table being vacuumed.
phase textCurrent processing phase of vacuum. See Table 28.41.
heap_blks_total bigintTotal number of heap blocks in the table. This number is reported as of the beginning of the scan; blocks added later will not be (and need not be) visited by this VACUUM.
heap_blks_scanned bigintNumber of heap blocks scanned. Because the visibility map is used to optimize scans, some blocks will be skipped without inspection; skipped blocks are included in this total, so that this number will eventually become equal to heap_blks_total when the vacuum is complete. This counter only advances when the phase is scanning heap.
heap_blks_vacuumed bigintNumber of heap blocks vacuumed. Unless the table has no indexes, this counter only advances when the phase is vacuuming heap. Blocks that contain no dead tuples are skipped, so the counter may sometimes skip forward in large increments.
index_vacuum_count bigintNumber of completed index vacuum cycles.
max_dead_tuples bigintNumber of dead tuples that we can store before needing to perform an index vacuum cycle, based on maintenance_work_mem.
num_dead_tuples bigintNumber of dead tuples collected since the last index vacuum cycle.

Autovacuum(重要)

这里中英文档差距挺大的,倡议看英文原版链接。了解主动垃圾回收的一些特点是有必要的,然而集体不太了解为什么这个货色在文档外面被藏到了一个层级目录比拟深的角落外面。

的确是角落,被放到了 Routine Vacuuming 最初一个大节简略提了一下。兴许是不想走漏过多细节让浏览人员难以了解?

本文也依据这个链接进行简略翻译和了解,会跳过一些内容,抽取要害局部进行介绍:

PostgreSQL: Documentation: 14: 25.1. Routine Vacuuming

PostgreSQL has an optional but highly recommended feature called autovacuum, whose purpose is to automate the execution of VACUUM and ANALYZE commands.

Postgresql 强烈推荐开启可选性能 autovacuum(其实根本都是默认开启的),他的底层工作原理是定期执行 VACUUM 和(VACUUM)ANALYZE 对于以后数据库实例的状况进行剖析。

The“autovacuum daemon”actually consists of multiple processes. There is a persistent daemon process, called the autovacuum launcher, which is in charge of starting autovacuum worker processes for all databases.

autovacuum daemon “ 实际上由多个过程组成。外部理论是长久的守护过程,叫做autovacuum launcher,它负责为所有数据库启动 autovacuum 工作过程。

这里有点像是线程池产生线程调配给请求者应用的思路。

Each worker process will check each table within its database and execute and/or as needed. log_autovacuum_min_duration can be set to monitor autovacuum workers activity.autovacuum_naptimeautovacuum_max_workersVACUUMANALYZE

每个工作过程将查看其数据库中的每个表并依据须要执行或者不执行。能够设置 log_autovacuum_min_duration 来监控 autovacuum 工作者的流动。

PS:最初的参数局部在官网文档模式是有 markdown 格局的 BUG,这里不纠结,不非常影响浏览。

If several large tables all become eligible for vacuuming in a short amount of time, all autovacuum.
Note that the number of running workers does not count towards max_connections or superuser_reserved_connections limits.

如果有好几个大表在很短的工夫内都有被主动垃圾回收选中,那么很可能导致主动垃圾回收的工作进度被拉长。

此外留神因为 Worker 线程的数量是无限的,所以对这些大表做清理的时候可能会导致其余的表垃圾无奈及时被回收。

须要留神正在运行的 worker 的数量 不计入max_connections or superuser_reserved_connections 限度。

Tables whose relfrozenxid value is more than autovacuum_freeze_max_age transactions old are always vacuumed, Otherwise, if the number of tuples obsoleted since the last VACUUM exceeds the“vacuum threshold”, the table is vacuumed.

这里理论解释能够被拆分为两个点:

  1. relfrozenxid值超过 autovacuum_freeze_max_age,存在旧事务(记录)的表总是被 VACUUM。
  2. 如果自上一次 VACUUM 以来,淘汰的元组数量 超过 了 “vacuum threshold” 设置的阈值,则表将被执行 VACUUM。

依据这两个点,能够关联出两个计算公式,垃圾回收阈值的计算公式,本次淘汰的元组触发 VACUUM 的阈值计算公式

垃圾回收阈值计算公式

上面探讨阈值的计算公式。

The vacuum threshold is defined as:

vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples

清理阈值 = 清理根本阈值 + 清理缩放系数 * 元组数

参数解释:

threshold(阈值):autovacuum_vacuum_threshold

vacuum scale factor(vacuum 比例系数):autovacuum_vacuum_scale_factor

number of tuples:元组(翻译叫图元,集体比拟承受元组这个翻译)数量。关联变量pg_class`reltuples`

如果自上一次 VACUUM 以来,淘汰的元组数量 超过 了 “vacuum threshold” 设置的阈值,则表将被执行 VACUUM。

同样有对应的计算公式

vacuum insert threshold = vacuum base insert threshold + vacuum insert scale factor * number of tuples

清理插入阈值 = 清理根底插入阈值 + 清理插入缩放系数 * 元组数

autovacuum_vacuum_insert_threshold:根本阈值

autovacuum_vacuum_insert_scale_factor:比例系数

这样的参数思考是容许局部的表被标识为 all visible,并且也能够容许元组被解冻,能够减小后续清理的工作须要。

两头局部省略大量内容,太长不看。

剖析阈值计算

For analyze, a similar condition is used: the threshold, defined as:

对于垃圾回收的剖析,Postgresql 也提供对应的计算公式

analyze threshold = analyze base threshold + analyze scale factor * number of tuples

剖析阈值 = 剖析根本阈值 + 剖析缩放系数 * 元组数

is compared to the total number of tuples inserted, updated, or deleted since the last .ANALYZE

比拟的根据是最初一次执行 VACUUM 之后插入、更新或删除的元组总数。

其余注意事项

Partitioned tables are not processed by autovacuum.

分区表不会被主动 VACUUM 解决。如果须要分区表清理,须要手动剖析和手动清理。

Temporary tables cannot be accessed by autovacuum. Therefore, appropriate vacuum and analyze operations should be performed via session SQL commands.

长期表不能被主动 vacuum 解决,vacuum 和 analyze 操作应该应用 Session 进行解决。

When multiple workers are running, the autovacuum cost delay parameters (see Section 20.4.4) are“balanced”among all the running workers, so that the total I/O impact on the system is the same regardless of the number of workers actually running.  However, any workers processing tables whose per-table autovacuum_vacuum_cost_delay or autovacuum_vacuum_cost_limit storage parameters have been set are not considered in the balancing algorithm.

这段话意味着如果存在并发 Worker 工作器并行工作,因为外部应用雷同的参数,所以外部会主动进行“重均衡”,所以无论 Worker 线程数量多,对系统的总 I / O 影响是雷同的。

对于这个机制存在影响的是在配置文件中对于某个被清理表设置了autovacuum_vacuum_cost_delay 或者 autovacuum_vacuum_cost_limit,那么重均衡的机制不会波及这些存在配置的表。

If a process attempts to acquire a lock that conflicts with the lock held by autovacuum, lock acquisition will interrupt the autovacuum.

此外如果一个过程试图获取一个与 autovacuum 持有的锁相抵触的锁,autovacuum 将会主动中断本人获取的锁。

上面这一段内容比拟重要,倡议重复浏览,尤其是加锁的一段内容。

Autovacuum workers generally don’t block other commands The default thresholds and scale factors are taken from postgresql.conf, ; see Storage Parameters for more information, If a setting has been changed via a table’s storage parameters, that value is used when processing that table; otherwise the global settings are used. See Section 20.10 for more details on the global settings.

主动垃圾回收线程不会烦扰其余用户线程的失常工作,默认的阈值和比例因子取自postgresql.conf,更多信息能够查看 Storage Parameters。如果通过表的存储参数扭转了某个设置,那么在解决该表时将应用该值;否则会应用默认的设置,全局设计能够浏览:Section 20.10

最初对于锁抵触的相干概念能够浏览上面的链接:PostgreSQL: Documentation: 14: 13.3. Explicit Locking

实际

VACUUM (VERBOSE, ANALYZE) onek;

当然不止这一些内容,后续会独自写一篇短文介绍利用垃圾回收和分析器去解决一些生产问题,这里临时留坑:

todo [[【Postgresql】Postgresql 数据库 INSERT 或 UPDATE 大量数据时速度慢的起因剖析]]

小结

了解 VACUUM 机制对于排查大数据量批量批改、插入、删除数据等问题至关重要,Postgresql 在数据清理这一块模拟了古代编程语言比拟容易了解的垃圾回收机制(至多浅层上只有稍加学习能够了解),所以这部分文档集体以目前认知程度还能承受的内容给“意译”了。

仔细观察这部分原文会发现波及了大量的参数配置,这些配置基本上是 DBA 或者对于 Postgresql 底层非常感兴趣才须要去探索的,当然有可能在某些非凡业务场景下须要调优参数,所以这里也算是打个预防针等问题降临的时候有个思路索引来排查问题。

集体英文程度抠脚,很多术语依照本人的认知进行翻译了,如果有谬误欢送指出。如果有什么中央不懂欢送一起探讨,因为我也不是很懂,哈哈,材料切实是太少了,老外探讨这玩意仿佛也不多,难顶。

不晓得为啥 Postgresql 这几年更新就像是坐火箭一样更新换代,然而国内用户问题反馈少的可怜,不过也算是好事件。比隔壁 Mysql 原地踏步强太多。

写在最初

Postgresql 的学习始终是比拟头痛的货色,参考资料和书籍都比拟老,大多数时候只能以官网文档学习和“猜想”为主,遇到一些我的项目问题不好排查。

PostgreSql 非常优良,也非常受到大厂欢送,然而实际上“保护老本”十分高,所以更倡议用 Mysql,尽管它在国外甚至连 Mysql 开发者到职后也称“越做越垃”。

正文完
 0