1. はじめに
本記事は、PostgreSQL16パフォーマンスチューニングシリーズの17対応版の一本です。
前回の記事でPostgreSQL16から17へのバージョンアップ手順を確認しました。本記事はその17環境を使って、WAL書き込み改善とVACUUM強化の2点をt3.microという低スペック環境で実測します。
SRA OSSの「PostgreSQL 17検証レポート」では大規模サーバ(多vCPU・大メモリ)での計測結果が示されています。本記事はt3.micro(2vCPU・1GiB)でも差が出るのかという切り口で検証します。
1.1 この記事でわかること
- WAL書き込み改善はt3.microで効果が出るのか
- VACUUMの速度・WAL出力量は16と17でどう変わるのか
- 低スペック環境でのPostgreSQL17の実力
2. 検証環境
2.1 環境構成
| 項目 | 内容 |
|---|---|
| OS | Amazon Linux 2023 |
| インスタンス | t3.micro(2vCPU・1GiB)EBS 30GB |
| PostgreSQL 16 | AMIから復元した16環境(16.12) |
| PostgreSQL 17 | 前回記事でバージョンアップした17環境(17.8) |
| データ規模 | pgbench -s 100(約1500万行) / VACUUM計測は300万行 |
2.2 postgresql.conf(16・17共通)
# === 今回の計測用設定 ===
# メモリ
shared_buffers = 256MB
work_mem = 4MB
maintenance_work_mem = 512MB
# 接続
max_connections = 200
# チェックポイント
checkpoint_timeout = 30min
checkpoint_completion_target = 0.9
max_wal_size = 1GB
# bgwriter(デフォルト維持)
bgwriter_delay = 200ms
bgwriter_lru_maxpages = 100
bgwriter_lru_multiplier = 2.0
# ログ
log_checkpoints = on
# VACUUM(計測中は自動実行を停止)
autovacuum = off
# 拡張(今回は不要)
# shared_preload_libraries = 'pg_stat_statements'
設定の考え方:今回はWAL改善とVACUUMの素の性能差を見たいため、チューニングは最小限にしています。過去記事(#3・#4)で使った劣化用・改善用の値は使わず、デフォルトに近い状態で16と17を比較します。
autovacuum = offは計測中に自動VACUUMが走って結果がブレるのを防ぐためです。計測後は必ずonに戻してください。
| パラメータ | デフォルト値 | 過去記事の値 | 今回の値 | 理由 |
|---|---|---|---|---|
shared_buffers |
128MB | 512MB / 8MB | 256MB | t3.microの1/4。基準値として |
work_mem |
4MB | 64MB / 128MB | 4MB | WAL/VACUUM計測に影響しない |
maintenance_work_mem |
64MB | 2GB | 512MB | t3.micro範囲内に収める |
max_connections |
100 | 400 | 200 | pgbench -c 50まで対応 |
checkpoint_timeout |
5min | 30s / 15min | 30min | 計測中にチェックポイントが走らないよう延長 |
checkpoint_completion_target |
0.9 | 0.001 / 0.9 | 0.9 | 劣化検証不要のためデフォルト |
max_wal_size |
1GB | 126MB / 4GB | 1GB | デフォルトのまま |
bgwriter_delay |
200ms | 10s / 100ms | 200ms | bgwriter影響を排除 |
bgwriter_lru_maxpages |
100 | 0 / 300 | 100 | bgwriter影響を排除 |
bgwriter_lru_multiplier |
2.0 | 2(参考) | 2.0 | デフォルトのまま |
log_checkpoints |
off | on | on | チェックポイント発生を監視 |
shared_preload_libraries |
(空) | 'pg_stat_statements' | (空) | 余計な負荷を排除 |
autovacuum |
on | - | off | 計測中の自動VACUUM実行を防ぐ |
2.3 設定の適用手順(16・17両環境で実施)
sudo vi /var/lib/pgsql/data/postgresql.conf
sudo systemctl restart postgresql
# 設定確認
psql -U postgres -d pgbench_test -c "SHOW shared_buffers;"
psql -U postgres -d pgbench_test -c "SHOW autovacuum;"
psql -U postgres -d pgbench_test -c "SHOW max_wal_size;"
2.4 pg_hba.confの設定
sudo vi /var/lib/pgsql/data/pg_hba.conf
# ローカル接続・TCP接続ともにscram-sha-256に統一
local all all scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
sudo systemctl restart postgresql
# 接続確認
psql -U postgres -d pgbench_test -c "SELECT version();"
3. WAL書き込み改善を実測する
3.1 背景
PostgreSQL 17ではWAL排他処理が改良され、高並列時の書き込みスループットが向上しました。64bit値のアトミックな交換をサポートするCPUで、多数の書き込みトランザクションの同時実行において性能改善が期待できます。
SRA OSSの検証レポートでは1024並列で大幅な差異が確認されています。t3.microの2vCPUでは並列数の上限が低いため、同様の差が出るかどうかを確認します。
3.2 実測コマンド
# スケール作成
pgbench -i -s 100 -U postgres pgbench_test
# 並列数を変えてTPS計測
for c in 5 10 20 50; do
echo "=== -c $c ==="
pgbench -c $c -j 2 -T 60 -U postgres pgbench_test
done
実行結果の例(-c 20 の場合):
=== -c 20 ===
pgbench (17.8)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 20
number of threads: 2
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 74066
number of failed transactions: 0 (0.000%)
latency average = 16.178 ms
initial connection time = 154.921 ms
tps = 1236.248538 (without initial connection time)
3.3 結果
| 並列数 | PG16 TPS | PG17 TPS | 差異 |
|---|---|---|---|
| -c 5 | 1,194.43 | 1,228.07 | +2.8% |
| -c 10 | 1,199.26 | 1,201.57 | +0.2% |
| -c 20 | 1,229.02 | 1,236.25 | +0.6% |
| -c 50 | 1,260.66 | 1,249.49 | -0.9% |
3.4 考察
t3.microでは16と17でほぼ同等の結果(±3%以内)となりました。
SRA OSSの検証レポートでも256並列・512並列まではほとんど性能向上が見られず、1024並列で初めて大幅な差異が出ています。 t3.microの2vCPUでは並列数の上限が低く、WAL排他処理の競合が発生しにくい環境のため、同様の傾向となりました。
WAL改善の恩恵を得るには多vCPU・高並列の環境が必要です。
4. VACUUMのメモリ・速度改善を実測する
4.1 背景
PostgreSQL 17ではVACUUMの内部実装が刷新されました。主な変更点は以下の通りです。
- dead tupleの整理とtuple凍結を一括で行い、WAL出力量を軽減
- インデックスのないテーブルのVACUUMを効率化
16.xまではVACUUM処理におけるメモリの使い方に課題があり、大量のdead tupleを処理する場合に本来不要なテーブルの再走査が発生していました。17ではこの課題が解消されています。
4.2 実測コマンド
# テーブル作成(300万行・インデックスあり)
psql -U postgres -d pgbench_test <<EOF
DROP TABLE IF EXISTS t_vacuum_test;
CREATE TABLE t_vacuum_test (id int, v text);
CREATE INDEX ON t_vacuum_test (id);
INSERT INTO t_vacuum_test
SELECT g, 'x' FROM generate_series(1, 3000000) g;
EOF
# 95%更新でdead tupleを発生させる
psql -U postgres -d pgbench_test -c "
UPDATE t_vacuum_test SET v = 'y' WHERE id % 20 != 1;"
# VACUUM実行時間を計測
psql -U postgres -d pgbench_test \
-c "\timing on" \
-c "VACUUM VERBOSE t_vacuum_test;"
実行結果の例(PostgreSQL 17・95%更新・インデックスあり):
Timing is on.
INFO: vacuuming "pgbench_test.public.t_vacuum_test"
INFO: finished vacuuming "pgbench_test.public.t_vacuum_test": index scans: 1
pages: 0 removed, 25885 remain, 25885 scanned (100.00% of total)
tuples: 2850000 removed, 3000000 remain, 0 are dead but not yet removable
removable cutoff: 567348, which was 0 XIDs old when operation ended
new relfrozenxid: 567346, which is 2 XIDs ahead of previous value
frozen: 10745 pages from table (41.51% of total) had 121418 tuples frozen
index scan needed: 13275 pages from table (51.28% of total) had 2850000 dead item identifiers removed
index "t_vacuum_test_id_idx": pages: 16454 in total, 0 newly deleted, 0 currently deleted, 0 reusable
avg read rate: 83.671 MB/s, avg write rate: 128.000 MB/s
buffer usage: 62293 hits, 19266 misses, 29473 dirtied
WAL usage: 68831 records, 24019 full page images, 75252272 bytes
system usage: CPU: user: 1.27 s, system: 0.12 s, elapsed: 1.79 s
VACUUM
Time: 1814.569 ms (00:01.815)
【注意】
max_wal_sizeは1GBに設定すること
max_wal_size = 4GBのままUPDATEを実行するとWALが蓄積してディスクが満杯になりPANICが発生します。VACUUM計測時は必ずmax_wal_size = 1GBに設定してください。
4.3 更新割合を変えたパターン
# テーブルを作り直してから各パターンを実施
# 50%更新
psql -U postgres -d pgbench_test <<EOF
DROP TABLE IF EXISTS t_vacuum_test;
CREATE TABLE t_vacuum_test (id int, v text);
CREATE INDEX ON t_vacuum_test (id);
INSERT INTO t_vacuum_test
SELECT g, 'x' FROM generate_series(1, 3000000) g;
EOF
psql -U postgres -d pgbench_test -c "
UPDATE t_vacuum_test SET v = 'y' WHERE id % 2 = 1;"
psql -U postgres -d pgbench_test \
-c "\timing on" \
-c "VACUUM VERBOSE t_vacuum_test;"
# 5%更新
psql -U postgres -d pgbench_test <<EOF
DROP TABLE IF EXISTS t_vacuum_test;
CREATE TABLE t_vacuum_test (id int, v text);
CREATE INDEX ON t_vacuum_test (id);
INSERT INTO t_vacuum_test
SELECT g, 'x' FROM generate_series(1, 3000000) g;
EOF
psql -U postgres -d pgbench_test -c "
UPDATE t_vacuum_test SET v = 'y' WHERE id % 20 = 1;"
psql -U postgres -d pgbench_test \
-c "\timing on" \
-c "VACUUM VERBOSE t_vacuum_test;"
# インデックスなし・95%更新
psql -U postgres -d pgbench_test <<EOF
DROP TABLE IF EXISTS t_vacuum_test;
CREATE TABLE t_vacuum_test (id int, v text);
INSERT INTO t_vacuum_test
SELECT g, 'x' FROM generate_series(1, 3000000) g;
EOF
psql -U postgres -d pgbench_test -c "
UPDATE t_vacuum_test SET v = 'y' WHERE id % 20 != 1;"
psql -U postgres -d pgbench_test \
-c "\timing on" \
-c "VACUUM VERBOSE t_vacuum_test;"
4.4 結果
実行時間
| 更新割合 | インデックス | PG16 | PG17 | 改善率 |
|---|---|---|---|---|
| 95% | あり | 10,431ms | 1,815ms | 約5.7倍高速 |
| 95% | なし | 511ms | 392ms | 約1.3倍高速 |
| 50% | あり | 1,913ms | 1,096ms | 約1.7倍高速 |
| 5% | あり | 413ms | 333ms | 約1.2倍高速 |
WAL出力量
| 更新割合 | インデックス | PG16 | PG17 | 削減率 |
|---|---|---|---|---|
| 95% | あり | 約226MB | 約71MB | 約69%削減 |
| 95% | なし | 約53MB | 約7.6MB | 約86%削減 |
| 50% | あり | 約168MB | 約34MB | 約80%削減 |
| 5% | あり | 約3.4MB | 約3.4MB | ほぼ同等 |
4.5 考察
インデックスあり95%更新で約5.7倍高速、WAL出力量は約69%削減という結果になりました。
注目すべきポイントは以下の3点です。
① インデックスの有無で改善率が大きく異なる
インデックスありの95%更新では5.7倍の改善に対し、インデックスなしでは1.3倍にとどまっています。17の改善はインデックスを持つテーブルのVACUUMで特に効果が大きくなっています。
② 更新割合が高いほど改善率が大きい
95%更新で5.7倍、50%更新で1.7倍、5%更新で1.2倍と、更新割合が高いほど改善率が大きくなっています。dead tupleが多いほど効果が出やすい傾向があります。
③ t3.microでも効果がはっきり出た
WAL改善とは対照的に、VACUUM改善はt3.microという低スペック環境でも明確な差が出ました。本番環境ではさらに大きな効果が期待できます。
5. まとめ
| 項目 | PG16 | PG17 | 結果 |
|---|---|---|---|
| TPS(並列50) | 1,260.66 | 1,249.49 | ほぼ同等(±1%) |
| VACUUM時間(95%・インデックスあり) | 10,431ms | 1,815ms | 約5.7倍高速 |
| VACUUM WAL出力(95%・インデックスあり) | 約226MB | 約71MB | 約69%削減 |
- WAL改善:t3.microでは差が出ない。恩恵を得るには256並列以上の高並列環境が必要
- VACUUM改善:t3.microでも劇的な効果。特にインデックスありの高更新率テーブルで顕著
6. 計測後の後片付け
# autovacuumを必ず戻す
sudo vi /var/lib/pgsql/data/postgresql.conf
# autovacuum = on に変更
sudo systemctl restart postgresql
psql -U postgres -d pgbench_test -c "SHOW autovacuum;"
7. 参考資料
| ページ | URL |
|---|---|
| PostgreSQL 17 リリースノート | https://www.postgresql.org/docs/17/release-17.html |
| SRA OSS PostgreSQL 17検証レポート | https://www.sraoss.co.jp/ |
8. さいごに
次回も、PostgreSQL17で改善された点について試していきたいと考えています。pgbenchを利用することで、大量のデータを利用した機能検証が容易に可能です。以前までの記事で、主にpostgresql.confの変更により、結果がどのように変わるかを見てきましたが、バージョンの差による機能差を見ていきたいと思います。