PG13并行vacuum
Vacuum是PG的一个重要功能用于回收表和索引中的死记录。如果没有这个功能,PG就会持续膨胀。本文介绍VACUUM命令中的PARALLEL选项,该选项于PG13引入。
VACUUM处理阶段
首先介绍下vacuum如何工作。无FULL选项的vacuum有5个阶段。例如,一个表有2个索引,工作阶段如下:
1)heap扫描阶段
扫描表,搜集需要回收的记录
2)索引vacuum阶段
一个一个的vacuum索引
3)heap vacuum阶段
Vacuum heap
4)索引清理阶段
一个一个地清理索引
5)heap truncate阶段
Truncate表的end的空页。
Heap scan阶段、index vacuum阶段和index清理阶段,vacuum使用visibility map跳过处理没有任何delete记录的页。例如btree索引,需要全索引扫描来清理死记录。Vacuum总是单进程一个一个处理索引。Vacuum一个大表需要花费很长时间,对用户来说非常恶心。
PARALLEL选项
为处理单进程vacuum问题,2016年我提出了一个并行vacuum的补丁。经历长时间审阅和修改后,PG13引入PARALLEL选项。通过这个选项,可以并行执行索引vacuum阶段和索引清理阶段。每个索引一个进程,但是自动vacuum中禁止并行vacuum。
不带任何整型参会的PARALLEL选项,根据表的索引个数自动计算并行度:
VACUUM(PARALLEL) tb1;
Leader进程总是处理一个索引,并行worker的最大个数为表索引个数-1,受限于max_parallel_maintenance_workers。目标索引必须大于等于min_parallel_index_scan_size。PARALLEL选项可以通过传入一个非0值指定并行度,有3个worker进程,共有4个并行进程:
VACUUM (PARALLEL 3) tb1;
默认情况开启PARALLEL选项。设置max_parallel_maintenance_workers为0禁止并行vacuum,或者指定PARALLEL 0:
VACUUM (PARALLEL 0) tbl; -- disable parallel vacuum
看下VACUUM VERBOSE输出,可以看到处理索引的进程:
VACUUM (PARALLEL, VERBOSE) tbl;
INFO: vacuuming "public.tbl"
INFO: launched 2 parallel vacuum workers for index vacuuming (planned: 2)
INFO: scanned index "i1" to remove 112834 row versions
DETAIL: CPU: user: 9.80 s, system: 3.76 s, elapsed: 23.20 s
INFO: scanned index "i2" to remove 112834 row versions by parallel vacuum worker
DETAIL: CPU: user: 10.64 s, system: 8.98 s, elapsed: 42.84 s
INFO: scanned index "i3" to remove 112834 row versions by parallel vacuum worker
DETAIL: CPU: user: 10.65 s, system: 8.98 s, elapsed: 43.96 s
INFO: "tbl": removed 112834 row versions in 112834 pages
DETAIL: CPU: user: 1.12 s, system: 2.31 s, elapsed: 22.01 s
INFO: index "i1" now contains 150000000 row versions in 411289 pages
DETAIL: 112834 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: index "i2" now contains 150000000 row versions in 411289 pages
DETAIL: 112834 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: index "i3" now contains 150000000 row versions in 411289 pages
DETAIL: 112834 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: "tbl": found 112834 removable, 112833240 nonremovable row versions in 553105 out of 735295 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 430046
There were 444 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 18.00 s, system: 8.99 s, elapsed: 91.73 s.
VACUUM
索引访问方法 vs 并行度
Vacuum并不是在所有情况下必行执行索引vacuum阶段和所以清理阶段。如果索引非常小,或者进程能够很快做完vacuum,发起并管理并行进程的消耗会造成开销。依赖于索引访问方法和索引大小,最好不要执行并行。
例如,vacuum一个很大的btree索引,可用并行执行索引vacuum阶段,因为需要执行全索引扫描,然而,如果索引vacuum由于没有死记录等原因没有执行vacuum时,则由一个并行vacuum worker执行索引清理阶段。Btree索引需要采集索引统计信息,这是在索引vacuum阶段执行的。Hash索引不需要在索引清理阶段扫描索引。
开发者为了支持不同类型的vacuum策略,通过设置IndexAmRoutine 的amparallelvacuumoptions域来完成。标签如下:
VACUUM_OPTION_NO_PARALLEL (默认):在上述两个阶段中禁止并行vacuum。
VACUUM_OPTION_PARALLEL_BULKDEL:索引vacuum阶段可以并行
VACUUM_OPTION_PARALLEL_COND_CLEANUP:如果索引vacuum阶段没有执行,索引清理节点可以并行
VACUUM_OPTION_PARALLEL_CLEANUP:及时索引vacuum阶段已经处理了该索引,索引清理阶段也可以并行:
nbtree |
Hash |
Gin |
gist |
spgist |
brin |
bloom |
|
VACUUM_OPTION_PARALLEL_BULKDEL |
Y |
Y |
Y |
Y |
Y |
Y |
|
VACUUM_OPTION_PARALLEL_COND_CLEANUP |
Y |
Y |
Y |
||||
VACUUM_OPTION_CLEANUP |
Y |
Y |
Y |
性能评估
环境:Core i7 2.6GHz, 16GB RAM, 512GB SSD
表大小6GB,8个3GB的索引,总大小30G,RAM不能放下所有数据。
索引vacuum的时间占总时间的95%。因此并行vacuum阶段可以显著减小执行时间。
原文
https://www.2ndquadrant.com/en/blog/parallelism-comes-to-vacuum/
Masahiko Sawada