ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

pgbench の scale オプションを知る

要約

PostgreSQLベンチマーク試験コマンドである pgbench の scale オプションは初期化処理で重要です。ベンチマーク実行時のオプションとしては有効でないことに注意が必要です。

$ pgbench -s 4 -c 1 -j 1 -t 10000 testdb
scale option ignored, using count from pgbench_branches table (1)

このようなワーニングが出力されたときはオプションの意味を勘違いしている可能性が高いため、注意が必要です。

対象バージョン

今回は PostgreSQL 11 で調査を行いました。

pgbench のマニュアルは以下を参照しています。
https://www.postgresql.jp/document/11/html/pgbench.html

「初期化用のオプション」と「ベンチマーク用オプション」の違い

pgbench は組み込みの TPC-B に似たシナリオを使うことも、独自のシナリオを使用することもできます。

組み込みのシナリオを実行するためには初期データ投入の初期化処理を実行する必要があります。これは pgbench コマンドを initialize (-i) オプション付きで実行します。

pgbench -i [ other-options ] dbname

PostgreSQL の pgbench のマニュアルには「初期化用のオプション」の記載がありますが、これはこの初期化処理で指定するオプション (other-options) に相当します。

初期化処理実行後はベンチマークを実行できます。pgbench コマンドを initialize (-i) オプション無しで実行します。

pgbench [ options ] dbname

PostgreSQL の pgbench のマニュアルには「ベンチマーク用オプション」の記載がありますが、これはこの初期化処理で指定するオプション (options) に相当します。

scale オプション

初期化用オプション

scale は初期データの「倍率」を指定します。デフォルトの「倍数」の 1 では以下の初期データ(行数)が生成されます。

テーブル 行数
pgbench_branches 1
pgbench_tellers 10
pgbench_accounts 100,000
pgbench_history 0

「倍率」を 100 (-s 100) に指定すると各テーブルの行数が100倍で生成されます。

テーブル 行数
pgbench_branches 100
pgbench_tellers 1,000
pgbench_accounts 10,000,000
pgbench_history 0

ベンチマーク用オプション

ドキュメントの説明を引用します。

pgbenchの出力で指定した倍率を報告します。 これは組み込みの試験では必要ありません。 正確な倍率がpgbench_branchesテーブルの行数を数えることで検出されます。 しかし、独自ベンチマーク(-fオプション)のみを試験している場合、このオプションを使用しない限り、倍率は1として報告されます。

pgbench

この説明を読むだけだと分かり辛い点があるので、組み込み試験の実行例を用いて説明します。

$ pgbench -i -s 10 testdb
dropping old tables...
creating tables...
generating data...
100000 of 1000000 tuples (10%) done (elapsed 0.07 s, remaining 0.62 s)
200000 of 1000000 tuples (20%) done (elapsed 0.44 s, remaining 1.76 s)
300000 of 1000000 tuples (30%) done (elapsed 0.78 s, remaining 1.83 s)
400000 of 1000000 tuples (40%) done (elapsed 1.03 s, remaining 1.54 s)
500000 of 1000000 tuples (50%) done (elapsed 1.20 s, remaining 1.20 s)
600000 of 1000000 tuples (60%) done (elapsed 1.72 s, remaining 1.14 s)
700000 of 1000000 tuples (70%) done (elapsed 2.08 s, remaining 0.89 s)
800000 of 1000000 tuples (80%) done (elapsed 3.17 s, remaining 0.79 s)
900000 of 1000000 tuples (90%) done (elapsed 3.46 s, remaining 0.38 s)
1000000 of 1000000 tuples (100%) done (elapsed 3.79 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.

$ pgbench -s 100 testdb
scale option ignored, using count from pgbench_branches table (10)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 1
number of threads: 1
number of transactions per client: 10
number of transactions actually processed: 10/10
latency average = 47.884 ms
tps = 20.883699 (including connections establishing)
tps = 20.980622 (excluding connections establishing)

初期化処理の scale オプションを "10" に指定して実行しました。

次にベンチマーク実行の scale オプションを "100" に指定して実行したところ、以下のワーニングが出力されました。

scale option ignored, using count from pgbench_branches table (10)

これは scale オプションを無視して pgbench_branches テーブルの行数を参照するとしています。()内はその行数を示しています。

そして、出力結果の "scaling factor" にはこの行数(つまり初期化処理の倍率)が出力されます。

scaling factor: 10

つまり、組み込みの試験でベンチマークを実行する際に scale オプションを指定することは意味がないとわかりました。

では組み込みの試験でなく、独自のシナリオで試験した場合にこの scale オプションがどう使われるかというと、単に "scaling factor" の出力に使われるだけのようです。
ソースコードを読んで判断しましたが、もし異なるようであればツッコミをお願いします。

scale オプションの値をどのように決定すべきか?

ドキュメントには「優れた実践 (Good Practices)」として以下の記載があります。

デフォルトのTPC-Bのような試験シナリオでは、初期倍率(-s)を試験予定のクライアント数(-c)の最大値と同程度にしなければなりません。 pgbench_branchesテーブルには-s行しかありません。 また、全トランザクションはその内の1つを更新しようとします。 ですので、-c値を-sより大きくすると、他のトランザクションを待機するためにブロックされるトランザクションが多くなることは間違いありません。

pgbench

ただ、私としては『初期倍率(-s)を試験予定のクライアント数(-c)の最大値と同程度にしなければなりません』が正しいかについて確信を持てないでいます。マニュアルではpgbench_branches テーブルの更新による競合を避けることを理由に挙げています。ですが、組み込み試験ではトランザクションの実行毎に参照もしくは更新する行を選択しており、どれほど初期倍率を大きくしたとしてもクライアント数が複数あれば競合する可能性を否定できないためです。

組み込みのTPC-Bのようなトランザクションの完全な定義を示します。

\set aid random(1, 100000 * :scale)
\set bid random(1, 1 * :scale)
\set tid random(1, 10 * :scale)
\set delta random(-5000, 5000)
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;

このスクリプトにより、トランザクションを繰り返す度に異なる、ランダムに選ばれた行を参照することができます。

pgbench

よって、マニュアルの推奨は一つの目安にしつつ、どのようなシナリオでベンチマークしたいのか?というのを都度考えるしかないと思われます。それによっては倍率オプションが 1 という選択肢もあるかもしれません。