TECH BLOG
技術ブログ
  • 2025-02-20 PostgreSQLPostgreSQL バージョンアップ

    PostgreSQL 17 で VACUUM がより効率よく実行されるようになりました。

本記事の概要

本記事では、PostgreSQL 17 で行われた VACUUM の改善について、実際に検証を行った結果を記載しています。

PostgreSQL 17 で行われた VACUUM の改善

PostgreSQL 16 以前では、VACUUM 時にインデックスをメンテナンスする際に利用できるメモリが 1 GB までという制約がありました。

これは内部的な仕様に基づく制限で、具体的には、不要タプルの TID (タプルを一意に特定する ID)を配列で持っていることが理由となります。

PostgreSQL 17 では、Adaptive Radix Tree (ART) と呼ばれるデータ構造に不要タプルの TID を保持するように改善され、その結果、効率的にメモリ領域を利用できるようになりました。

実際に検証

では、実際に PostgreSQL 16 と 17 で、VACUUM を行い、その実行速度を確認してみます。

検証に利用した環境

検証に利用した環境は下記となります。

  • RockyLinux 9.3
  • PostgreSQL 16.6
  • PostgreSQL 17.2

VACUUM の速度比較

pgbench のデータを利用して、VACUUM の実行速度を比較しました。
検証の手順は下記となります。

  1. pgbench の初期化(pgbench -i)
  2. 以下の 2 手順を 3 回繰り返す
    • pgbench_accounts テーブルに対して更新
    • pgbench_accounts テーブルに対して VACUUM(←この時間を計測)

上記の検証を行った結果をまとめたものを下記に記載します。

PostgreSQL 16 と 17 の VACUUM 実行時間の比較(平均)

VACUUM を 3 回 行い、その 3 回の実行時間の平均をまとめたものが下記となります。
※長いので下の方にある「結果から分かること」を見ていただければと思います。

No テーブルサイズ maintenance_work_mem 廃止行の割合 v16の実行時間(平均) v17の実行時間(平均) v16との差 v16との比率
1 128MB 100MB 3% 390.93 ms 267.12 ms -123.81 ms 68.33%
2 128MB 100MB 20% 577.25 ms 381.33 ms -195.92 ms 66.06%
3 128MB 100MB 50% 920.76 ms 509.63 ms -411.13 ms 55.35%
4 128MB 100MB 70% 1,391.13 ms 728.74 ms -662.39 ms 52.38%
5 128MB 1GB 3% 300.69 ms 299.27 ms -1.42 ms 99.53%
6 128MB 1GB 20% 514.78 ms 347.94 ms -166.84 ms 67.59%
7 128MB 1GB 50% 896.07 ms 577.41 ms -318.66 ms 64.44%
8 128MB 1GB 70% 1,198.84 ms 796.36 ms -402.48 ms 66.43%
9 128MB 2GB 3% 366.10 ms 315.88 ms -50.22 ms 86.28%
10 128MB 2GB 20% 508.27 ms 339.60 ms -168.67 ms 66.81%
11 128MB 2GB 50% 846.66 ms 516.81 ms -329.85 ms 61.04%
12 128MB 2GB 70% 948.73 ms 717.32 ms -231.40 ms 75.61%
13 1.2GB 100MB 3% 1,255.49 ms 737.16 ms -518.32 ms 58.72%
14 1.2GB 100MB 20% 1,899.89 ms 1,341.61 ms -558.27 ms 70.62%
15 1.2GB 100MB 50% 3,672.44 ms 3,404.83 ms -267.62 ms 92.71%
16 1.2GB 100MB 70% 6,105.10 ms 5,231.51 ms -873.59 ms 85.69%
17 1.2GB 1GB 3% 1,466.26 ms 667.71 ms -798.55 ms 45.54%
18 1.2GB 1GB 20% 2,172.92 ms 1,355.85 ms -817.07 ms 62.40%
19 1.2GB 1GB 50% 3,644.15 ms 3,031.56 ms -612.60 ms 83.19%
20 1.2GB 1GB 70% 6,436.27 ms 5,500.77 ms -935.49 ms 85.47%
21 1.2GB 2GB 3% 1,451.44 ms 720.35 ms -731.09 ms 49.63%
22 1.2GB 2GB 20% 1,829.87 ms 1,367.44 ms -462.43 ms 74.73%
23 1.2GB 2GB 50% 4,157.50 ms 2,746.27 ms -1,411.23 ms 66.06%
24 1.2GB 2GB 70% 6,188.14 ms 4,995.54 ms -1,192.60 ms 80.73%
25 6.4GB 100MB 3% 1,781.20 ms 1,178.79 ms -602.41 ms 66.18%
26 6.4GB 100MB 20% 5,146.64 ms 3,901.61 ms -1,245.02 ms 75.81%
27 6.4GB 100MB 50% 18,773.99 ms 13,423.18 ms -5,350.81 ms 71.50%
28 6.4GB 100MB 70% 95,888.70 ms 53,907.74 ms -41,980.96 ms 56.22%
29 6.4GB 1GB 3% 3,011.47 ms 1,334.37 ms -1,677.10 ms 44.31%
30 6.4GB 1GB 20% 7,101.87 ms 3,767.97 ms -3,333.90 ms 53.06%
31 6.4GB 1GB 50% 16,404.66 ms 14,138.50 ms -2,266.16 ms 86.19%
32 6.4GB 1GB 70% 88,320.60 ms 43,842.30 ms -44,478.31 ms 49.64%
33 6.4GB 2GB 3% 2,938.97 ms 1,070.92 ms -1,868.05 ms 36.44%
34 6.4GB 2GB 20% 6,806.48 ms 3,380.05 ms -3,426.43 ms 49.66%
35 6.4GB 2GB 50% 16,694.91 ms 13,610.78 ms -3,084.14 ms 81.53%
36 6.4GB 2GB 70% 88,428.00 ms 51,531.61 ms -36,896.39 ms 58.28%
PostgreSQL 16 と 17 の VACUUM 実行時間の比較(最小)

VACUUM を 3 回 行い、その 3 回の実行時間のうち、一番実行時間が小さかったものをまとめたものが下記となります。
※長いので下の方にある「結果から分かること」を見ていただければと思います。

No テーブルサイズ maintenance_work_mem 廃止行の割合 v16の実行時間(最小) v17の実行時間(最小) v16との差 v16との比率
1 128MB 100MB 3% 345.03 ms 197.04 ms -147.99 ms 57.11%
2 128MB 100MB 20% 550.83 ms 317.57 ms -233.26 ms 57.65%
3 128MB 100MB 50% 811.89 ms 376.69 ms -435.20 ms 46.40%
4 128MB 100MB 70% 1,242.48 ms 631.82 ms -610.66 ms 50.85%
5 128MB 1GB 3% 275.71 ms 291.66 ms 15.95 ms 105.78%
6 128MB 1GB 20% 425.07 ms 259.84 ms -165.23 ms 61.13%
7 128MB 1GB 50% 841.99 ms 550.52 ms -291.46 ms 65.38%
8 128MB 1GB 70% 999.68 ms 749.50 ms -250.18 ms 74.97%
9 128MB 2GB 3% 331.10 ms 298.45 ms -32.65 ms 90.14%
10 128MB 2GB 20% 495.26 ms 258.04 ms -237.22 ms 52.10%
11 128MB 2GB 50% 784.74 ms 426.77 ms -357.97 ms 54.38%
12 128MB 2GB 70% 912.72 ms 583.05 ms -329.67 ms 63.88%
13 1.2GB 100MB 3% 968.59 ms 557.47 ms -411.12 ms 57.55%
14 1.2GB 100MB 20% 1,540.69 ms 1,268.17 ms -272.52 ms 82.31%
15 1.2GB 100MB 50% 3,416.94 ms 3,194.94 ms -222.00 ms 93.50%
16 1.2GB 100MB 70% 5,577.01 ms 4,696.38 ms -880.63 ms 84.21%
17 1.2GB 1GB 3% 970.80 ms 551.41 ms -419.39 ms 56.80%
18 1.2GB 1GB 20% 1,946.36 ms 1,327.45 ms -618.91 ms 68.20%
19 1.2GB 1GB 50% 3,545.97 ms 2,832.72 ms -713.26 ms 79.89%
20 1.2GB 1GB 70% 6,209.32 ms 5,433.36 ms -775.96 ms 87.50%
21 1.2GB 2GB 3% 1,017.17 ms 368.57 ms -648.60 ms 36.23%
22 1.2GB 2GB 20% 1,600.13 ms 1,341.08 ms -259.05 ms 83.81%
23 1.2GB 2GB 50% 3,997.26 ms 2,518.52 ms -1,478.74 ms 63.01%
24 1.2GB 2GB 70% 5,632.03 ms 4,040.26 ms -1,591.77 ms 71.74%
25 6.4GB 100MB 3% 750.96 ms 483.44 ms -267.51 ms 64.38%
26 6.4GB 100MB 20% 4,880.01 ms 3,147.09 ms -1,732.92 ms 64.49%
27 6.4GB 100MB 50% 17,287.59 ms 12,782.95 ms -4,504.64 ms 73.94%
28 6.4GB 100MB 70% 88,237.58 ms 41,811.85 ms -46,425.74 ms 47.39%
29 6.4GB 1GB 3% 2,003.05 ms 702.85 ms -1,300.19 ms 35.09%
30 6.4GB 1GB 20% 6,735.83 ms 3,139.77 ms -3,596.06 ms 46.61%
31 6.4GB 1GB 50% 15,545.11 ms 13,828.69 ms -1,716.42 ms 88.96%
32 6.4GB 1GB 70% 79,510.03 ms 31,694.82 ms -47,815.21 ms 39.86%
33 6.4GB 2GB 3% 1,958.47 ms 692.47 ms -1,266.00 ms 35.36%
34 6.4GB 2GB 20% 6,522.35 ms 3,198.40 ms -3,323.95 ms 49.04%
35 6.4GB 2GB 50% 16,282.01 ms 13,033.16 ms -3,248.85 ms 80.05%
36 6.4GB 2GB 70% 78,676.40 ms 42,381.07 ms -36,295.33 ms 53.87%

「v16との差」には「PostgreSQL 17 の実行時間 - PostgreSQL 16 の実行時間」したものを記載しています。数値が小さいほど、PostgreSQL 17 の方が高速化に実行されたことを表しています。
「v16との比率」には「PostgreSQL 17 の実行時間 / PostgreSQL 16 の実行時間」したものを記載しています。数値が小さいほど、PostgreSQL 17 の方が高速化に実行されたことを表しています。

結果から分かること

PostgreSQL 16 では「テーブルサイズが大きい」「廃止行の割合が少ない」場合、maintenance_work_mem が大きくなるにつれて VACUUM の実行時間も大きくなることを確認できました(No.25、No.29、No33)。
こういった事象は PostgreSQL 17 では見られませんので、PostgreSQL 17 では、やはり VACUUM 処理が効率よく行われていると判断できます。

その他の改善内容

今回は検証しておりませんが、VACUUM の実行速度のほかにメモリ使用量の削減や WAL 出力量の削減などが行われているようです。
逆にいうと、そういったメモリ使用量を削減するように改善されているから VACUUM の処理速度が向上している、とも言えます。
おおよそ PostgreSQL 16 と比較してメモリの使用量は 1/20 程度になっているとの情報があります(ページ内のどの部分に廃止行が存在しているかによって、効率化の度合いが変わるようです)。

また、PostgreSQL 16 以前では、maintenance_work_mem に 1 GB を超える値を設定しても、VACUUM 時にディスク領域が利用される可能性がありました。
この制約がPostgreSQL 17 での改善により無くなり、処理対象のデータが maintenance_work_mem に収まるサイズであれば、すべてメモリ領域で処理されるようになっています。

まとめ

本記事では、PostgreSQL 16 と PostgreSQL 17 での VACUUM の実行時間を検証し、比較した結果を確認しました。
VACUUM 処理は PostgreSQL を安定運用するためにも定期的に行う重要な処理となっています。VACUUM 処理が効率よく行えるようになったということは、より安定的な運用が可能になったことに繋がります。
PostgreSQL 16 以前と PostgreSQL 17 以降で maintenance_work_mem に設定する値(の目安や基準)も変わると思いますので、次回以降の記事で、そのあたりを確認できればと考えています。

CATEGORY

ARCHIVE

PostgreSQLに関するご相談は
株式会社インサイトまで
お気軽にお問い合わせください。

CONTACT