TECH BLOG
技術ブログ
  • 2025-11-30 PostgreSQLPostgreSQL ナレッジ

    PostgreSQLのバージョン間の性能差を検証(2)

本記事の概要

前回( https://www.insight-ltd.co.jp/tech_blog/postgresql/pg_versionup/947/ )は、PostgreSQL のバージョン 15〜18 において、pgbench のベンチマークスクリプトを利用して性能を比較しました。
今回は、pgbench のテーブルを利用してパラレルクエリなどの SQL の性能を比較を行います。

検証

検証は、前回と同じく以下の環境で実施しました。

  • RockyLinux 9.6
  • PostgreSQL 15.14
  • PostgreSQL 16.10
  • PostgreSQL 17.6
  • PostgreSQL 18.0

各バージョンとも、同一サーバ上でビルド・初期化を行い、同一設定で実施しています。
shared_buffers や work_mem などは、マシンスペックに合わせて一般的な目安とされている値に設定しました。

検証方法

下記の SQL を pgbench コマンドの -f に指定して、ベンチマークテストを実施しました。

検証に利用した SQL
# SQL 1 ( DISTINCT の改善 )
SELECT DISTINCT bid, aid FROM pgbench_accounts ORDER BY bid, aid LIMIT 10000;

# SQL 2 ( UNION ALL の改善 )
( SELECT aid FROM pgbench_accounts WHERE bid BETWEEN 1 AND 100  ORDER BY aid )
UNION ALL
( SELECT aid FROM pgbench_accounts WHERE bid BETWEEN 101 AND 200 ORDER BY aid )
ORDER BY aid;

# SQL 3 ( GROUP BY の改善 )
SELECT aid, bid, max(abalance) FROM pgbench_accounts GROUP BY aid, bid; 

# SQL 4 ( GROUPING SETS の改善 )
SELECT bid, sum(abalance) AS s FROM pgbench_accounts GROUP BY GROUPING SETS ((bid), ()) HAVING sum(abalance) > 100000;

前回と同じく 2 パターンのデータサイズで性能を測定しました。

データサイズ = 約 650 MB でのテスト

テストに利用したコマンドは下記となります。

$ pgbench -i -s 50
$ pgbench -c 1 -j 1 -T 300 -f <SQLファイル>
$ pgbench -c 24 -j 12 -T 600 -f <SQLファイル>
データサイズ = 約 6.5 GB でのテスト

テストに利用したコマンドは下記となります。

$ pgbench -i -s 500
$ pgbench -c 24 -j 12 -T 4000 -f <SQLファイル>

オプションの意味は

  • -i は、データベースの初期化
  • -s は、初期化するデータベースのスケール(サイズ、データ件数)
  • -c は、テストの同時接続数
  • -j は、テストのスレッド数
  • -T は、テストの実行時間(秒)

となります。
「データサイズ = 約 650 MB でのテスト」では、1 接続(並列)と 24 接続(並列)で SQL 実行されています。
「データサイズ = 約 6.5 GB でのテスト」では、24 接続(並列)で SQL 実行されています。

「データサイズ = 約 650 MB でのテスト」の結果

「データサイズ = 約 650 MB でのテスト」の結果を、各バージョンごとに比較したものが下記となります。

1 接続(並列)での結果

バージョン count TPS min max p95 p99
15 18 回 0.060 t/s 15,936.472 ms 17,100.576 ms 16,997.326 ms 17,100.576 ms
16 21 回 0.068 t/s 14,076.489 ms 15,482.081 ms 15,265.680 ms 15,482.081 ms
17 22 回 0.070 t/s 13,937.872 ms 15,328.112 ms 15,281.396 ms 15,328.112 ms
18 22 回 0.073 t/s 13,590.447 ms 15,064.642 ms 13,834.356 ms 15,064.642 ms

各項目の説明は下記となります。

  • count: 実行されたトランザクション数。
  • tps: 1秒あたりに処理されたトランザクション数。
  • min: 実行時間の最小値。最も短いトランザクション処理時間です。
  • max: 実行時間の最大値。最も遅いトランザクション処理時間です。
  • p95: 全トランザクションのうち 95% が、この時間以下で完了したことを表しています。
  • p99: 全トランザクションのうち 99% が、この時間以下で完了したことを表しています。

24 接続(並列)での結果

1 接続(並列)では試行回数が少なかったため、24 接続(並列)でも確認しました。

バージョン count TPS min max p95 p99
15 293 回 0.479 t/s 24,761.036 ms 87,856.245 ms 58,411.654 ms 61,983.926 ms
16 312 回 0.531 t/s 24,896.716 ms 89,808.145 ms 78,537.596 ms 84,098.765 ms
17 296 回 0.551 t/s 20,170.504 ms 132,029.828 ms 121,815.829 ms 126,652.246 ms
18 321 回 0.564 t/s 21,607.231 ms 132,780.028 ms 87,353.457 ms 95,587.210 ms

「データサイズ = 約 6.5 GB でのテスト」の結果

「データサイズ = 約 6.5 GB でのテスト」の結果を、各バージョンごとに比較したものが下記となります。

バージョン count TPS min max p95 p99
15 179 回 0.044 t/s 308,085.567 ms 728,357.052 ms 694,875.877 ms 705,954.848 ms
16 183 回 0.045 t/s 311,889.801 ms 689,353.586 ms 635,016.792 ms 674,919.096 ms
17 188 回 0.046 t/s 289,807.476 ms 740,415.678 ms 631,550.352 ms 715,843.183 ms
18 180 回 0.045 t/s 292,632.183 ms 756,750.662 ms 693,733.770 ms 717,640.867 ms

検証結果から確認できること

結果から下記のことを確認できました。

  1. データサイズが小さい場合、バージョンと性能が比例していた。
    • 特にバージョン 15 から 16 の性能向上が、その他のバージョン間よりも大きい。
  2. データサイズが大きい場合、バージョンによる性能差は見られなかった

上記の結果となった理由について、実行計画から読み解けるかを確認します。

実行計画の確認(データサイズ = 約 650 MB)

「データサイズ = 約 650 MB でのテスト」について、v15 と v18 の実行計画を比較して、どのような差異があるのかを確認します。
差異が分かりやすいものを 1 つ抜粋して、v15 と v18 の実行計画を、それぞれ下記に記載します。

v15 の実行計画

下記が v15 の実行計画です。
SQL の実行時間はおおよそ 8.2 sec となっています。

EXPLAIN (ANALYZE, BUFFERS) SELECT aid, bid, max(abalance) FROM pgbench_accounts GROUP BY aid, bid;
                                                             QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=156968.00..206968.00 rows=5000000 width=12) (actual time=4644.430..7646.144 rows=5000000 loops=1)
   Group Key: aid
   Batches: 5  Memory Usage: 524337kB  Disk Usage: 31504kB
   Buffers: shared hit=81968, temp read=3566 written=6589
   ->  Seq Scan on pgbench_accounts  (cost=0.00..131968.00 rows=5000000 width=12) (actual time=0.024..727.782 rows=5000000 loops=1)
         Buffers: shared hit=81968
 Planning:
   Buffers: shared hit=30 read=2
 Planning Time: 0.232 ms
 Execution Time: 8212.458 ms
(10 rows)

v18 の実行計画

下記が v18 の実行計画です。
SQL の実行時間はおおよそ 6.7 sec となっています。

EXPLAIN (ANALYZE, BUFFERS) SELECT aid, bid, max(abalance) FROM pgbench_accounts GROUP BY aid, bid;
                                                              QUERY PLAN                                                               
---------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=156968.00..206968.00 rows=5000000 width=12) (actual time=4133.848..6249.216 rows=5000000.00 loops=1)
   Group Key: aid
   Batches: 1  Memory Usage: 327705kB
   Buffers: shared hit=81968
   ->  Seq Scan on pgbench_accounts  (cost=0.00..131968.00 rows=5000000 width=12) (actual time=0.030..621.958 rows=5000000.00 loops=1)
         Buffers: shared hit=81968
 Planning:
   Buffers: shared hit=7 read=2
 Planning Time: 0.889 ms
 Execution Time: 6731.028 ms
(10 rows)

実行計画の差異

v15 と v18 の実行計画を比較しても、処理ノードの順序など、大きな違いはありませんでした。
実行計画が変わらないのは、結合するテーブルの数が少なく、SQL が比較的シンプルであることが理由だと考えられます。
v15 と v18 の実行計画の主な違いは、メモリの消費量が v18 の方が少ないことが挙げられます。
上記の実行計画例では、v15 ではディスク領域が利用されているのに対し、v18 ではメモリ領域のみでハッシュ処理が行われています。

また、データサイズが大きい場合にバージョンによる性能差が見られなかったのは、データ量に対してメモリサイズが不足しており、ディスク領域を利用した処理が発生しているためでした。

まとめ

今回の検証で、PostgreSQL のバージョンが上がるにつれて、SQL 実行時のメモリ消費量が抑えられ、結果として SQL 実行速度が向上することを確認できました。
ただ、今回の検証は、比較的シンプルな SQL を、インサイト社内での環境で実行した結果である点にご留意ください。
実際の運用で実行されている数多くのテーブルを結合している複雑な SQL では、今回の結果と異なる可能性があります。
性能検証の際には、実際の運用で使用されている SQL やワークロードを用いることが推奨となります。

CATEGORY

ARCHIVE

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

CONTACT