★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

pgbench

pgbenchPostgreSQLに対してベンチマーク試験を行う

概要

pgbench -i [option...] [dbname]

pgbench [option...] [dbname]

説明

pgbenchPostgreSQL上でベンチマーク試験を行う単純なプログラムです。 これは同一のSQLコマンドの並びを何度も実行します。複数の同時実行データベースセッションで実行することもできます。 そして、トランザクションの速度(1秒当たりのトランザクション数)の平均を計算します。 デフォルトでpgbenchは、1トランザクション当たり5つのSELECTUPDATEINSERTコマンドを含むおおよそTPC-Bに基いたシナリオを試験します。 しかし、独自のトランザクションスクリプトファイルを作成することで他の試験ケースを簡単に実行することができます。

pgbenchの典型的な出力を以下に示します。

transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 10
number of threads: 1
maximum number of tries: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
number of failed transactions: 0 (0.000%)
latency average = 11.013 ms
latency stddev = 7.351 ms
initial connection time = 45.758 ms
tps = 896.967014 (without initial connection time)

最初の7行はいくつかの最重要パラメータの設定を表示しています。 6行目では、直列化エラーまたはデッドロックエラーのあるトランザクションの最大試行回数がレポートされます(詳細は直列化の失敗/デッドロック再試行を参照してください)。 8行目では、完了トランザクション数と予定したトランザクション数がレポートされます(後者は単なるクライアント数とクライアント毎のトランザクション数の積算結果です。) これらは、完了前に実行が失敗した場合や一部のSQLコマンドが失敗した場合を除いて等しくなります(-Tモードでは、実際のトランザクション数のみが出力されます)。 次の行では、直列化エラーまたはデッドロックエラーが原因で失敗したトランザクション数がレポートされます(直列化の失敗/デッドロック再試行を参照してください)。 最後の行は1秒当たりのトランザクション数を示します。

デフォルトのTPC-Bと似たトランザクション試験では、あらかじめ設定する特定のテーブルが必要です。 これらのテーブルを作成し、データを投入するためには、-i(初期化)オプションを付けてpgbenchを呼び出さなければなりません。 (独自スクリプトを試験する場合、この手順は必要ありません。 しかし代わりに試験に必要な何らかの設定を行わなければならないでしょう。) 初期化は以下のようになります。

pgbench -i [ other-options ] dbname

ここでdbnameは試験用に前もって作成されたデータベースの名前です。 (またデータベースサーバの接続方法を指定するために、-h-p-Uが必要になるかもしれません。)

注意

pgbench -iは4つのテーブルpgbench_accountspgbench_branchespgbench_historypgbench_tellersを作成します。 もしあればこうした名前のテーブルは破壊されます。 もし同じ名前のテーブルが存在する場合にはよく注意してください。

デフォルトの倍率の1では、テーブルは初期状態で以下の行数を含みます。

table                   # of rows
---------------------------------
pgbench_branches        1
pgbench_tellers         10
pgbench_accounts        100000
pgbench_history         0

-s(倍率)オプションを使用して行数を増加させることができます(また、ほとんどの目的ではおそらく増加させるべきです)。 また、-F (fillfactor)オプションをここで使用しても構いません。

一度この必要な設定を行った後、以下のように-iを持たないコマンドでベンチマークを行うことができます。

pgbench [ options ] dbname

ほとんどすべての場合、有用な試験とするためにいくつかのオプションが必要になります。 最重要オプションは-c(クライアント数)、-t(トランザクション数)、-T (制限時間)、-f(独自スクリプトファイルの指定)です。 以下の全一覧を参照してください。

オプション

以下では、データベース初期化時に使用されるオプション、ベンチマーク実行時に使用されるオプション、どちらの場合でも使われるオプションの3つに分けて説明します。

初期化用のオプション

pgbenchは以下の初期化用のコマンドライン引数を受け付けます。

dbname #

試験するデータベースの名前を指定します。 これが指定されていない場合、環境変数PGDATABASEが使用されます。 この変数も設定されていない場合は、接続のために指定されたユーザ名が使用されます。

-i
--initialize #

初期化モードを呼び出すために必要です。

-I init_steps
--init-steps=init_steps #

標準の初期化ステップの内、選択したものだけを実行します。 init_stepsでは、各ステップ毎に1文字を使って、実行する初期化ステップを指定します。 各ステップは指定した順で実行されます。 デフォルトはdtgvpです。 有効なステップは以下の通りです。

d (Drop) #

既存のpgbenchのテーブルを全て削除します。

t (create Tables) #

標準のpgbenchシナリオで使われるテーブル、すなわちpgbench_accountspgbench_branchespgbench_historyおよびpgbench_tellersを作成します。

gまたはG (Generate data, クライアント側、またはサーバ側) #

データを生成し、既存データを置き換えて、標準の各テーブルに読み込みます。

g(クライアント側データ生成)は、データはpgbenchクライアントで生成されてからサーバに送られます。 これはCOPYでクライアント/サーバの帯域を大きく使います。 pgbenchは、バージョン14またはそれ以降のPostgreSQLを持つフリーズオプションを使用して、パーティションが有効になっていない限り、その後のVACUUMを高速化します。 gを使うと、pgbench_accountsテーブルのためにデータを生成する間、100,000行毎にメッセージを1つログ出力するようになります。

G(サーバ側データ生成)では、小さな問い合わせだけがpgbenchクライアントから送られ、データは実際にはサーバで生成されます。 こちらは帯域を著しく要求することはありませんが、サーバが、より多くの作業をすることになります。 Gを使うと、データを生成する間は進捗メッセージをログ出力しなくなります。

デフォルトの初期化動作は、クライアント側のデータ生成(gと同じ)を使います。

v (Vacuum) #

標準の各テーブルに対してVACUUMを実行します。

p (create Primary keys) #

標準の各テーブルにプライマリキーインデックスを作成します。

f (create Foreign keys) #

標準のテーブル間に外部キー制約を作成します。 (このステップはデフォルトでは実行されないことに注意してください)

-F fillfactor
--fillfactor=fillfactor #

指定したfillfactorでpgbench_accountspgbench_tellerspgbench_branchesテーブルを作成します。 デフォルトは100です。

-n
--no-vacuum #

初期化でバキュームを実行しません。 (このオプションは-Iで指定されていたとしても初期化ステップvを抑止します。)

-q
--quiet #

ログ処理を、5秒に1つの進行メッセージのみを生成する静寂モードに切り替えます。 デフォルトのログ処理では、100,000行毎にメッセージを1つ出力し、(特に優れたハードウェアでは)1秒当たりに多くのメッセージを出力します。

-Iの中でGが指定されていれば、この設定は影響しません。

-s scale_factor
--scale=scale_factor #

この倍率で生成される行数を積算します。 例えば、-s 100pgbench_accountsテーブルに10,000,000行を生成することを意味します。 デフォルトは1です。 この倍率が20000以上になると、アカウント識別子の範囲を保持できる程度に大きくなるように、アカウント識別子を保持するために使用される列(aid列)はより大きな整数(bigint)を使用するように切り替わります。

--foreign-keys #

標準テーブル間で外部キー制約を作成します。 (このオプションは初期化ステップの並びに、もし無かったならfステップを追加します。)

--index-tablespace=index_tablespace #

デフォルトのテーブル空間ではなく、指定したテーブル空間の中にインデックスを作成します。

--partition-method=NAME #

NAMEメソッドでパーティション化されたpgbench_accountsテーブルを作成します。 期待される値はrangeまたはhashです。 このオプションは--partitionsが0でない値に設定されていることを要求します。 指定されなければ、デフォルトはrangeです。

--partitions=NUM #

アカウントの数に比例したほぼ等しい大きさのNUM個のパーティションにパーティション化されたpgbench_accountsテーブルを作成します。 デフォルトは0で、パーティション化しないことを意味します。

--tablespace=tablespace #

デフォルトのテーブル空間ではなく、指定したテーブル空間の中にテーブルを作成します。

--unlogged-tables #

永続テーブルではなくログを取らないテーブルとしてテーブルを作成します。

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

pgbenchは以下のベンチマーク用コマンドライン引数を受け付けます。

-b scriptname[@weight]
--builtin=scriptname[@weight] #

指定の組み込みスクリプトを実行するスクリプトのリストに追加します。 利用可能な組み込みのスクリプトは、tpcb-likesimple-updateselect-onlyです。 組み込みの名前の曖昧な接頭辞も受け付けられます。 特別な名前listを使うと、組み込みスクリプトのリストを表示して、即座に終了します。

オプションで、@の後に整数のweight(重み)を書くことで、他のスクリプトと比較してそのスクリプトが選ばれる確率を調整することができます。 デフォルトの重みは1です。 詳細は以下を参照してください。

-c clients
--client=clients #

模擬するクライアント数、つまり、同時に実行されるデータベースセッション数です。 デフォルトは1です。

-C
--connect #

各クライアントセッションが一度だけ接続を確立するのではなく、各トランザクションが新しい接続を確立します。 これは接続オーバーヘッドを測定する場合に有用です。

-d
--debug #

デバッグ用出力を表示します。

-D varname=value
--define=varname=value #

独自スクリプト(後述)で使用される変数を定義します。 複数の-Dオプションを使用することができます。

-f filename[@weight]
--file=filename[@weight] #

filenameから読み取ったトランザクションスクリプトを実行されるスクリプトのリストに追加します。

オプションで、@の後に整数のweight(重み)をつけることで、他のスクリプトと比較してそのスクリプトが選ばれる確率を調整することができます。 デフォルトの重みは1です。 (@文字を含むスクリプトファイル名を使用するには、 filen@me@1 のように曖昧さがないように重みを付けます。) 詳細は以下を参照してください。

-j threads
--jobs=threads #

pgbench内のワーカースレッド数です。 複数のスレッドを使用することはマルチCPUマシンで有用になります。 クライアントは利用可能なスレッドの間でできる限り均等に分散されます。 デフォルトは1です。

-l
--log #

各トランザクションに関する情報をログファイルに書き出します。 詳細は以下を参照してください。

-L limit
--latency-limit=limit #

limitミリ秒以上続くトランザクションが計数され、別途遅いトランザクションとして報告されます。

制限が使用されると(--rate=...)、limitミリ秒以上遅延がスケジュールされたトランザクションは遅延制限を満たす可能性がないため、サーバに送信されることは決してありません。 これらのトランザクションは計数され、別途スキップされたとして報告されます。

--max-triesオプションが使用されている場合、直列化異常またはデッドロックのために失敗したトランザクションは、すべての試行の合計時間がlimitより大きい場合、再試行されません。 試行回数ではなく試行時間のみを制限するには、--max-tries=0を使用します。 デフォルトでは、--max-triesオプションは1に設定されており、直列化エラー/デッドロックエラーのあるトランザクションは再試行されません。 このようなトランザクションの再試行の詳細は直列化の失敗/デッドロック再試行を参照してください。

-M querymode
--protocol=querymode #

サーバへ問い合わせを送信するために使用するプロトコルです。

  • simple: 簡易問い合わせプロトコルを使用します。

  • extended: 拡張問い合わせプロトコルを使用します。

  • prepared: プリペアドステートメントを伴う拡張問い合わせプロトコルを使用します。

preparedモードでは、pgbenchは問い合わせの2回目の繰り返しからは構文解析結果を再利用しますので、pgbenchは他のモードよりも速く動作します。

デフォルトは簡易問い合わせプロトコルです。 (詳しい情報は第55章を参照してください)

-n
--no-vacuum #

試験を実行する前にバキュームを行いません。 pgbench_accountspgbench_branchespgbench_historypgbench_tellers標準テーブルを含まない独自試験シナリオを実行する場合、このオプションは必要です。

-N
--skip-some-updates #

組み込みのsimple-update(単純な更新)のスクリプトを実行します。 -b simple-updateの短縮形です。

-P sec
--progress=sec #

sec秒毎の進捗レポートを表示します。 レポートには起動からの経過時間、前回レポート時からのTPS、前回レポート時からのトランザクションの平均待ち時間、標準偏差、最後のレポートからの失敗したトランザクションの数を含んでいます。 (-R)オプションによる制限下では、待ち時間はトランザクションの実開始時間ではなく、予定開始時間で算出されていますので、平均予定遅延時間が含まれています。 --max-triesを使用して直列化エラー/デッドロックエラー後のトランザクション再試行を有効にする場合、レポートには再試行されたトランザクションの数とすべての再試行の回数が含まれます。

-r
--report-per-command #

ベンチマークの終了後、各コマンドについて、文ごとの平均待機時間(クライアントから見た実行時間)、失敗回数、およびこのコマンドの直列化エラーまたはデッドロックエラー後の再試行回数の統計をレポートします。 レポートに再試行統計が表示されるのは、--max-triesオプションが1以外の場合のみです。

-R rate
--rate=rate #

トランザクションを可能な限り高速(デフォルト)で実行するのではなく、指定された目標レートで実行します。 レートは1秒あたりのトランザクション数で与えられます。目標レートが実施可能な最大レートを越えている場合、レート制限は結果に影響を与えません。

レートはトランザクションの開始予定タイムラインがポアソン分布に沿う事を目標としています。 期待される開始時刻の予定は、前トランザクションの終了時ではなくクライアントの初期起動時に基づいて動かします。 このアプローチはトランザクションがオリジナルの終了予定時刻を過ぎた場合でも、後でまた追い付けることを意味します。

制限がアクティブになると、実行終了時に報告されるトランザクション待ち時間は、予定開始時刻から計算されるので、 各トランザクションが前トランザクションの終了を待たねばならなかった時間を含んでいます。 この待ち時間はスケジュールラグタイムと呼ばれ、平均と最大値も別々に報告されます。 実トランザクション開始時刻についてのトランザクション待ち時間、つまりデータベース内でトランザクションの実行に要した時間は、報告された待ち時間からスケジュールラグタイムを減算することで算出することができます。

--latency-limit--rateと一緒に指定された場合、トランザクションは、先行するトランザクションが終了した際にすでに遅延制限を超えていて、非常に遅れてしまうことがあり得ます。 そのようなトランザクションはサーバに送信さることなくスキップされ、別途カウントされます。

スケジュールラグタイムの高い値は、システムが選択されたクライアント数とスレッド数で、指定されたレートでトランザクションを処理できなかったことを示しています。 トランザクションの平均実行時間が各トランザクション間で予定されていた間隔より長い場合、各逐次トランザクションは更に遅くなり、 スケジュールラグタイムはテスト実行がより長く増加し続けます。 これが起こる場合、指定トランザクションレートを減らす必要があります。

-s scale_factor
--scale=scale_factor #

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

-S
--select-only #

組み込みのselect-only(SELECTのみ)のスクリプトを実行します。 -b select-onlyの短縮形です。

-t transactions
--transactions=transactions #

各クライアントが実行するトランザクション数です。 デフォルトは10です。

-T seconds
--time=seconds #

クライアントあたりのトランザクション数を固定で指定するよりも長くテストを実行したい場合、ここに指定した秒数でテストを実行します。 -t-Tは互いに排他的です。

-v
--vacuum-all #

試験前に4つの標準テーブルすべてをバキュームします。 -n-vもなければ、pgbenchpgbench_tellerspgbench_branchesテーブルをバキュームし、pgbench_history内のデータをすべて消去します。

--aggregate-interval=seconds #

集約間隔の長さ(秒単位)です。 これは-lと一緒でのみ使用できます。 このオプションを付けると、ログには以下で説明するような指定間隔単位の要約が含まれます。

--failures-detailed #

トランザクションごとおよび集約ログ、メインレポートおよびスクリプトごとのレポートで、次のタイプにグループ化された失敗をレポートします。

  • 直列化失敗

  • デッドロック障害

詳細については、直列化の失敗/デッドロック再試行を参照してください。

--log-prefix=prefix #

--logにより作成されるログファイルのファイル名の先頭につける文字列を設定します。 デフォルトはpgbench_logです。

--max-tries=number_of_tries #

直列化エラー/デッドロックエラーのあるトランザクションの再試行を有効にし、これらの試行の最大数を設定します。 このオプションは、すべてのトランザクション試行の合計時間を制限する--latency-limitオプションと組み合せることができます。 また、--latency-limitまたは--timeを指定せずに試行回数を無制限に使用することはできません(--max-tries=0)。 デフォルト値は1で、直列化エラー/デッドロックエラーのあるトランザクションは再試行されません。 このようなトランザクションの再試行の詳細は、直列化の失敗/デッドロック再試行を参照してください。

--progress-timestamp #

進捗を表示(-Pオプション)しているとき、実行開始以後の経過秒数の代わりにタイムスタンプ(Unixエポック時刻)を使用します。 単位は秒で、ドットの後にミリ秒の精度が付きます。 これは様々なツールで生成されたログを比較するのに役立つでしょう。

--random-seed=seed #

ランダムジェネレータのシードを設定します。 各スレッド毎の初期ジェネレータ状態から一連の値を生成する、システム乱数ジェネレータの種となります。 seedの値は以下が可能です。 time(デフォルト、現在時刻に基づくシード)、rand(強いランダムソースを使用、使用できなければ失敗します)、あるいは符号無し整数値です。 ランダムジェネレータはpgbenchスクリプト(random...関数)から明示的に、あるいは暗黙に(例えばオプション--rateがトランザクションのスケジュールに使用します)、実行されます。 明示的に設定した場合、シードに使われる値はターミナルにあらわれます。 seedに与えることのできる値は何であれ、環境変数PGBENCH_RANDOM_SEEDを通して付与しても良いです。 設定したシードがありうる全ての実行に影響を及ぼすようにするためには、本オプションを最初に置くか、環境変数を使ってください。

明示的にシードを設定することは、乱数に関しては、正確にpgbench実行を再現することを可能にします。 ランダム状態はスレッド毎に制御されているので、スレッド毎に一つのクライアントであり、外的な依存やデータ依存が無い場合、同一の起動に対して正確に同じpgbench実行することを意味します。 統計的観点からは、性能のばらつきを隠したり、例えば前回実行と同じページにヒットすることで不当に性能改善するので、正確な再現実行は悪い考えです。 しかしながら、例えばエラーを起こすトリッキーなケースを再実行するなど、デバッグには大きな助けとなるでしょう。 賢く使ってください。

--sampling-rate=rate #

データをログに書き出す際に使用される、生成されるログの量を減少するためのサンプリング割合です。 このオプションが指定された場合、指定された割合のトランザクションがログに残ります。 1.0はすべてのトランザクションが、0.05はトランザクションの5%のみがログに残ることを意味します。

ログファイルを処理する際にはこのサンプリング割合を考慮することを忘れないでください。 例えば、TPS値を計算する際には、比例した数を掛け合わせなければなりません(例:サンプリング割合が0.01の場合実際のTPSの1/100を得るだけです。)

--show-script=scriptname #

組み込みスクリプトscriptnameの実際のコードを標準エラーに出力し、即座に終了します。

--verbose-errors #

すべてのエラーと失敗(再試行しないエラー)に関するメッセージを表示します。 これには、どの再試行制限を超えたか、および直列化/デッドロックの失敗でどの程度超えたかが含まれます(この場合、出力が大幅に増加することに注意してください)。 詳細は直列化の失敗/デッドロック再試行を参照してください。

共通オプション

pgbenchは接続パラメータとして以下の共通コマンドライン引数も受け付けます。

-h hostname
--host=hostname #

データベースサーバのホスト名

-p port
--port=port #

データベースサーバのポート番号

-U login
--username=login #

接続ユーザ名

-V
--version #

pgbenchのバージョンを表示し、終了します。

-?
--help #

pgbenchのコマンドライン引数の説明を表示し、終了します。

終了ステータス

実行に成功すればステータス0で終了します。 終了ステータス1は、無効なコマンドラインオプションや発生しないと思われる内部エラーなどの静的の問題を示します。 最初のコネクションの失敗など、ベンチマークの起動時に発生する初期エラーも、終了ステータス1になります。 データベースエラーやスクリプトでの問題などの実行中のエラーは終了ステータス2になります。 後者の場合、pgbenchは部分的な結果を表示します。

環境

PGDATABASE
PGHOST
PGPORT
PGUSER #

デフォルトの接続パラメータです。

このユーティリティは、他のほとんどのPostgreSQLユーティリティと同様、libpqでサポートされる環境変数を使用します(34.15を参照してください)。

環境変数PG_COLORは診断メッセージで色を使うかどうかを指定します。 可能な値はalwaysautoneverです。

注釈

pgbenchで実際に実行されるトランザクションは何か?

pgbenchは指定したリストからランダムに選択したテストスクリプトを実行します。 これには-bの組み込みスクリプトと-fのユーザ定義カスタムスクリプトが含まれることがあります。 各スクリプトには@の後に指定される相対的な重みを与えることができ、それが選ばれる確率を変更することができます。 デフォルトの重みは1です。 重みが0のスクリプトは無視されます。

デフォルトの組み込みトランザクションスクリプト(-b tpcb-likeとすることでも実行されます)は、aidtidbiddeltaからランダムに選択され、トランザクション毎に7つのコマンドを発行します。 このシナリオはTPC-Bベンチマークに示唆を受けたものですが、実際にはTPC-Bではないので、この名前になっています。

  1. BEGIN;

  2. UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

  3. SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

  4. UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

  5. UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

  6. INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

  7. END;

simple-updateの組み込みを選択した(あるいは-Nを指定した)場合、第4ステップと第5ステップはトランザクションに含まれません。 これにより、これらのテーブルに対する更新の競合を避けられますが、テストケースはさらにTPC-Bらしくなくなります。

select-onlyの組み込みを選択した(あるいは-Sを指定した)場合、SELECTのみが発行されます。

独自スクリプト

pgbenchは、ファイルから読み込んだトランザクションスクリプト(-fオプション)でデフォルトのトランザクションスクリプト(上述)を置き換えて独自のベンチマークシナリオを実行する機能をサポートします。 この場合、トランザクションはスクリプトファイルの1回の実行として数えられます。

スクリプトファイルにはセミコロンで終了するSQLコマンドが1つ以上含まれます。 空行および--から始まる行は無視されます。 スクリプトファイルの行には、pgbench自身が解釈するメタコマンド(後述)も記述することができます。

注記

PostgreSQLの9.6より前では、スクリプトファイル内のSQLコマンドは改行で終了しており、そのため行をまたがって継続することができませんでした。 これからは連続するSQLコマンドを区切るためにセミコロンが必要です(ただし、SQLコマンドの後にメタコマンドが続く場合は、セミコロンは必要ありません)。 pgbenchの古いバージョンと新しいバージョンの両方で動作するスクリプトを作る必要があるなら、各SQLコマンドを1行で書き、終わりにセミコロンを付けるようにしてください。

pgbenchスクリプトにはSQLトランザクションの不完全なブロックが含まれていないと想定されています。 実行時にクライアントが最後のトランザクションブロックを完了せずにスクリプトの最後に到達した場合、クライアントは中断されます。

スクリプトファイル向けの簡単な変数置換機能があります。 変数名は最初の文字が数字以外で文字(非ラテン文字を含む)、数字およびアンダースコアで構成されていなければなりません。 上で説明したように変数を-Dコマンドラインオプションで設定することができます。 また、後で説明するようにメタコマンドで設定することもできます。 -Dコマンドラインオプションで設定された変数の他に、表 293に記載されているように、自動的に設定される変数がいくつかあります。 -D を使ってこれらの変数に設定された値は、自動設定の値より優先されます。 一度設定すると、変数の値は、:variablenameと書かれてSQLコマンドに挿入されます。 1つ以上のクライアントセッションが実行される場合、セッション毎に独自の変数群を持ちます。 pgbenchは1つの文内で255個までの変数の利用をサポートします。

表293 pgbench Automatic Variables

変数説明
client_id クライアントセッションを識別する一意の数値(ゼロから始まる)
default_seed デフォルトでハッシュ関数や疑似ランダム置換関数で使われるシード
random_seed ランダムジェネレータのシード(-Dで上書きされていないなら)
scale 現在の倍率

スクリプトファイルのメタコマンドはバックスラッシュ(\)から始まり、通常は行末まで続きますが、バックスラッシュと改行を書くことで、追加の行に続けることができます。 メタコマンドへの引数は空白文字で区切られます。 以下のメタコマンドがサポートされています。

\gset [prefix] \aset [prefix] #

このコマンドは、終了を意味するセミコロン(;)の置き換えで、SQL問い合わせを終えるために使われます。

\gsetコマンドが使われると、それまでのSQL問い合わせは1行を返すものと期待され、その行の列は列名にちなんだ名前の変数に格納されます。prefixが指定されていれば、変数名の前に付きます。

\asetコマンドが使われると、(\;で分けられた)すべての結合したSQL問い合わせは、その列が列名にちなんだ名前の変数に格納されます。prefixが指定されていれば、変数名の前に付きます。 問い合わせが行を返さなければ、割り当ては行なわれませんので、これを検出するために変数の存在をテストできます。 問い合わせが2行以上返した場合、最後の値が保持されます。

\gset\asetはパイプラインモードでは使用できません。 これは、コマンドで必要になるまでに問い合わせの結果がまだ利用できないためです。

以下の例は、最初の問い合わせからの最終的な口座残高を変数abalanceに入れ、変数p_twop_threeを3番目の問い合わせからの整数で埋めます。 2番目の問い合わせの結果は捨てられます。 最後の2つの結合した問い合わせの結果は、変数fourfiveに格納されます。

UPDATE pgbench_accounts
  SET abalance = abalance + :delta
  WHERE aid = :aid
  RETURNING abalance \gset

-- 2つの問い合わせの組み合わせ
SELECT 1 \;
SELECT 2 AS two, 3 AS three \gset p_
SELECT 4 AS four \; SELECT 5 AS five \aset
\if expression
\elif expression
\else
\endif #

このコマンド群はpsql\if expressionと似た、入れ子にできる条件ブロックを実現します。 条件式は\setと同じで、非ゼロ値は真と解釈されます。

\set varname expression #

varname変数をexpressionから計算された値に設定します。 式(expression)には、NULL定数、真理値定数のTRUEFALSE5432のような整数の定数、3.14159のような倍精度実数の定数、変数を参照する :variablename、通常のSQLの優先度と結合規則での演算子関数呼び出し、SQLのCASE一般条件式および括弧を含むことができます。

関数と大部分の演算子はNULL入力にNULLを返します。

条件の用途では非ゼロの数値はTRUE、ゼロ数値とNULLFALSEです。

大きすぎるもしくは小さすぎる整数や倍精度実数の定数は、整数算術演算子(+-*/)と同様にオーバーフローエラーになります。

CASEに最後のELSE句が与えられないとき、デフォルト値はNULLです。

\set ntellers 10 * :scale
\set aid (1021 * random(1, 100000 * :scale)) % \
           (100000 * :scale) + 1
\set divx CASE WHEN :x <> 0 THEN :y/:x ELSE NULL END
\sleep number [ us | ms | s ] #

スクリプトの実行をマイクロ秒(us)、ミリ秒(ms)、秒(s)単位で指定した間待機させます。 単位を省略した場合、デフォルトは秒です。 numberは整数定数か整数値を持つ変数への:variablename参照のいずれかです。

\sleep 10 ms
\setshell varname command [ argument ... ] #

commandシェルコマンドを指定のargumentで実行した結果をvarname変数に設定します。 このコマンドは標準出力を通して整数値を返さなければなりません。

commandおよび各argumentは、テキスト定数または変数を参照する:variablenameとすることができます。 コロンから始まるargumentを使用したい場合、argumentの先頭にさらにコロンを付けなければなりません。

例:

\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
\shell command [ argument ... ] #

\setshellと同じですが、コマンドの結果は廃棄されます。

例:

\shell command literal_argument :variable ::literal_starting_with_colon
\startpipeline
\endpipeline #

これらのコマンドは、SQL文のパイプラインの開始と終了を区切ります。 パイプラインモードでは、文は前の文の結果を待つことなくサーバに送信されます。 詳細は34.5を参照してください。 パイプラインモードでは、拡張問い合わせプロトコルを使用する必要があります。

組み込み演算子

表 294に載っている算術、ビットごと、比較、論理の演算子はpgbenchに組み込まれていて、\setの式で使用できます。 演算子は優先度の低い順に載っています。 注意書きがある場合を除いて、2つの数値を取る演算子は、入力の片方が倍精度実数であれば倍精度実数の値を結果とし、そうでなければ整数の結果になります。

表294 pgbenchの演算子

演算子

説明

boolean OR booleanboolean

論理OR

5 or 0TRUE

boolean AND booleanboolean

論理AND

3 and 0FALSE

NOT booleanboolean

論理NOT

not falseTRUE

boolean IS [NOT] (NULL|TRUE|FALSE)boolean

ブール値のテスト

1 is nullFALSE

value ISNULL|NOTNULLboolean

NULLであるかのテスト

1 notnullTRUE

number = numberboolean

等価

5 = 4FALSE

number <> numberboolean

不等

5 <> 4TRUE

number != numberboolean

不等

5 != 5FALSE

number < numberboolean

より小さい

5 < 4FALSE

number <= numberboolean

以下

5 <= 4FALSE

number > numberboolean

より大きい

5 > 4TRUE

number >= numberboolean

以上

5 >= 4TRUE

integer | integerinteger

ビット毎のOR

1 | 23

integer # integerinteger

ビット毎のXOR

1 # 32

integer & integerinteger

ビット毎のAND

1 & 31

~ integerinteger

ビット毎のNOT

~ 1-2

integer << integerinteger

ビット毎の左シフト

1 << 24

integer >> integerinteger

ビット毎の右シフト

8 >> 22

number + numbernumber

加算

5 + 49

number - numbernumber

減算

3 - 2.01.0

number * numbernumber

乗算

5 * 420

number / numbernumber

除算(入力が両方とも整数であれば、結果は0に向けて丸められる)

5 / 31

integer % integerinteger

剰余(余り)

3 % 21

- numbernumber

符号反転

- 2.0-2.0


組み込み関数

表 295に示す関数はpgbenchに組み込まれており、\setに現れる式の中で使うことができます。

表295 pgbenchの関数

関数

説明

abs ( number ) 入力と同じ型

絶対値

abs(-17)17

debug ( number ) 入力と同じ型

引数をstderrに出力し、引数を返す。

debug(5432.1)5432.1

double ( number ) → double

倍精度実数にキャストする。

double(5432)5432.0

exp ( number ) → double

指数(eの指定した冪)

exp(1.0)2.718281828459045

greatest ( number [, ... ] ) → double if any argument is double, else integer

引数の中で最大の値を選択する。

greatest(5, 4, 3, 2)5

hash ( value [, seed ] ) → integer

これはhash_murmur2の別名です。

hash(10, 5432)-5817877081768721676

hash_fnv1a ( value [, seed ] ) → integer

FNV-1aハッシュを計算する。

hash_fnv1a(10, 5432)-7793829335365542153

hash_murmur2 ( value [, seed ] ) → integer

MurmurHash2ハッシュを計算する。

hash_murmur2(10, 5432)-5817877081768721676

int ( number ) → integer

整数にキャストする。

int(5.4 + 3.8)9

least ( number [, ... ] ) → double if any argument is double, else integer

引数の中で最小の値を選択する。

least(5, 4, 3, 2.1)2.1

ln ( number ) → double

自然対数

ln(2.718281828459045)1.0

mod ( integer, integer ) → integer

剰余(余り)

mod(54, 32)22

permute ( i, size [, seed ] ) → integer

[0, size)の範囲のiの順列値。 これは、seedによってパラメータ化された整数0...size-1の疑似ランダム置換におけるi(modulo size)の新しい位置です。 以下を参照してください。

permute(0, 4) 0と3の間の整数

pi () → double

πの近似値

pi()3.14159265358979323846

pow ( x, y ) → double

power ( x, y ) → double

xy

pow(2.0, 10)1024.0

random ( lb, ub ) → integer

[lb, ub]内の一様分布の整数の乱数を計算する。

random(1, 10) 1と10の間の整数

random_exponential ( lb, ub, parameter ) → integer

[lb, ub]内の指数分布の整数の乱数を計算する、後述。

random_exponential(1, 10, 3.0) 1と10の間の整数

random_gaussian ( lb, ub, parameter ) → integer

[lb, ub]内のガウス分布の整数の乱数を計算する、後述。

random_gaussian(1, 10, 2.5) 1と10の間の整数

random_zipfian ( lb, ub, parameter ) → integer

[lb, ub]内のジップ分布の整数の乱数を計算する、後述。

random_zipfian(1, 10, 1.5) 1と10の間の整数

sqrt ( number ) → double

平方根

sqrt(2.0)1.414213562


random関数は一様分布を使って値を生成します。 つまり、すべての値は指定された範囲内で同じ確率で発生します。 random_exponentialrandom_gaussian、および、random_zipfian関数は追加の倍精度実数のパラメータを必要とし、それによって分布の正確な形が決まります。

  • 指数分布では、parameterが分布を制御します。 急速に減少する指数分布をparameterで切り捨て、境界範囲内の整数に射影します。 正確には、以下の式に従います。


    f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))

    これにより、minmaxの間(両端を含む)の間の値if(i) - f(i + 1)の確率で生成されます。

    直感的には、parameterが大きければ、minに近い値が発生する確率が高くなり、maxに近い値が発生する確率が低くなります。 parameterが0に近ければ、発生の分布はより平ら(より一様)になります。 大雑把に分布を近似すると、minに近い最頻の1%の範囲の値は、parameter%の割合で発生します。 parameterの値は厳密に正でなければなりません。

  • ガウス分布では、標準的な正規分布(古典的なベルの形をしたガウス曲線)で、左に-parameter、右に+parameterのところで切り捨てられたものに間隔が射影されます。 間隔の中間の値が発生する確率が最も高くなります。 正確に言うと、PHI(x)は標準正規分布の累積分布関数、平均値mu(max + min) / 2.0と定義し、さらに


    f(x) = PHI(2.0 * parameter * (x - mu) / (max - min + 1)) /
           (2.0 * PHI(parameter) - 1)

    とすると、minmaxの間(両端を含む)の値iが発生する確率はf(i + 0.5) - f(i - 0.5)になります。 直感的には、parameterが大きくなれば、間隔の中間に近い値になる確率が高く、また、minmaxの境界に近い値になる確率は低くなります。 約67%の値は、中間の1.0 / parameterの範囲、つまり平均値から0.5 / parameterの範囲から、また95%は中間の2.0 / parameterの範囲、つまり平均値から1.0 / parameterの範囲に発生します。 例えばparameterが4.0なら、67%の値は間隔の中間の4分の1(1.0/4.0)から(つまり3.0 / 8.0から5.0 / 8.0まで)、95%は間隔の中間の半分(2.0 / 4.0)から(2番目と3番目の四分位)から発生します。 許される最小のparameter値は2.0です。

  • random_zipfianは制限付きのジップ分布を生成します。 parameterはどれほど歪んだ分布かを定義します。 より大きいparameterほど、より高頻度に区間の始点に近い値が描かれます。 範囲が1から始まるとして、kを描く確率とk+1を描く確率の比が((k+1)/k)**parameterという分布になります。 例えば、random_zipfian(1, ..., 2.5)は、値12の約(2/1)**2.5 = 5.66倍高い頻度で生成し、値23の約(3/2)**2.5 = 2.76倍高い頻度で生成し、以下同様に続きます。

    pgbenchの実装は「Non-Uniform Random Variate Generation」Luc Devroye(Springer 1986, p. 550-551)に基づいており、parameter値は[1.001, 1000]の範囲に限定されています。

注記

行を不均一に選択するベンチマークを設計する場合、選択された行はシーケンスからのIDや物理的な行の順序など他のデータと相関している可能性があり、性能測定に影響を与える可能性があることに留意してください。

これを避けるには、permute関数、または同様の効果を持つ他の追加手順を使用して、選択した行をシャッフルし、そのような相関関係を削除することをお勧めします。

ハッシュ関数hashhash_murmur2およびhash_fnv1aは入力値とオプションシードパラメータを受け付けます。 シードが与えられなかった場合、:default_seedの値が使われます。これは、コマンドライン-Dオプションで設定されない限りランダムに初期化されたものです。

permuteは、入力値とサイズとオプションシードパラメータを受け付けます。 [0, size)の範囲の整数の疑似ランダム置換を生成し、並べ替えられた値の入力値のインデックスを返します。 選択される並べ替えはシードによってパラメータ化され、指定されていない場合:default_seedがデフォルトになります。 ハッシュ関数とは異なり、permuteは出力値に衝突や穴がないことを保証します。 区間外の入力値は、サイズを法として解釈されます。サイズが正でない場合、関数はエラーを発生させます。 permuterandom_zipfianrandom_exponentialのような不均一なランダム関数の分布を分散させて、より頻繁に導出される値が自明に相関しないようにすることができます。 たとえば、以下のpgbenchスクリプトは、僅かなアカウントが過大な負荷を生成するソーシャルメディアやブログのプラットフォームで起こりえる現実世界のワークロードをシミュレートします。

\set size 1000000
\set r random_zipfian(1, :size, 1.07)
\set k 1 + permute(:r, :size)

一部のケースでは、互いに無関係ないくつかの異なる分布が必要で、これはオプションのシードパラメータが役立ちます。

\set k1 1 + permute(:r, :size, :default_seed + 123)
\set k2 1 + permute(:r, :size, :default_seed + 321)

同様の動作は、hashでも近似的に行うことができます。

\set size 1000000
\set r random_zipfian(1, 100 * :size, 1.07)
\set k 1 + abs(hash(:r)) % :size

しかし、hashは衝突を発生させるため、到達できない値もあれば、元の分布から予想されるよりも頻度が高い値もあります。

例えば、組み込みの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;

このスクリプトにより、トランザクションを繰り返す度に異なる、ランダムに選ばれた行を参照することができます。 (この例はまた、各クライアントセッションがなぜ独自の変数を持つことが重要なのかも表しています。 これがないと、異なる行を独立して参照することができないのです。)

トランザクション毎のログ処理

--aggregate-intervalオプションなしで)-lオプションを使用すると、pgbenchは各トランザクションに関する情報をログファイルに書き出します。 ログファイルの名前はprefix.nnnで、prefixのデフォルトはpgbench_lognnnpgbenchプロセスのPIDです。 ファイル名の先頭の文字列は--log-prefixオプションを使って変更することができます。 -jオプションが2以上で複数のワーカースレッドがある場合、それぞれが独自のログファイルを持つことになります。 最初のワーカーは標準的な単一ワーカーの場合と同じ名前を持つログファイルを使用します。 他のワーカー用の追加のログファイルはprefix.nnn.mmmと命名され、ここでmmmは1から始まる各ワーカーの連番です。

ログファイルの各行には1つのトランザクションが記述されています。 このログファイルには、スペースで区切られた次のフィールドが含まれています:

client_id

トランザクションを実行したクライアントセッションを示します

transaction_no

そのセッションで実行されたトランザクションの数をカウントします

time

トランザクションの経過時間(マイクロ秒)

script_no

トランザクションに使用されたスクリプトファイルを示します(複数のスクリプトが-fまたは-bで指定されている場合に便利です)

time_epoch

トランザクションの完了時刻(Unixエポックタイムスタンプ)

time_us

トランザクションの完了時間の分数秒部分(マイクロ秒)

schedule_lag

トランザクション開始遅延、つまりトランザクションのスケジュールされた開始時刻と実際に開始された時刻の差をマイクロ秒単位で表したものです(--rateが指定されている場合にのみ存在します)

retries

直列化エラーまたはトランザクション中のデッドロックエラー後の再試行のカウントします (--max-triesが1でない場合にのみ存在する)

--rate--latency-limitの両方を使用すると、スキップされたトランザクションのtimeskippedとして報告されます。 トランザクションが失敗で終了した場合、timefailedとして報告されます。 --failures-detailedオプションを使用すると、失敗したトランザクションのtimeは、障害のタイプに応じて直列化またはデッドロックとして報告されます(詳細は直列化の失敗/デッドロック再試行を参照してください)。

単一クライアントでの実行で生成されたログファイルの一部を示します。

0 199 2241 0 1175850568 995598
0 200 2465 0 1175850568 998079
0 201 2513 0 1175850569 608
0 202 2038 0 1175850569 2663

--rate=100--latency-limit=5を指定した例を示します。(schedule_lag列が追加されていることに注意)

0 81 4621 0 1412881037 912698 3005
0 82 6173 0 1412881037 914578 4304
0 83 skipped 0 1412881037 914578 5217
0 83 skipped 0 1412881037 914578 5099
0 83 4722 0 1412881037 916203 3108
0 84 4142 0 1412881037 918023 2333
0 85 2465 0 1412881037 919759 740

この例では、トランザクション82は遅延(6.173ミリ秒)が5ミリ秒を越えており、遅れています。 次の2つのトランザクションは、開始する前にすでに遅れてしまっているため、スキップされています。

次の例は、最大試行回数を10に設定した失敗と再試行のログファイルの一部を示しています(追加再試行列に注意)。

3 0 47423 0 1499414498 34501 3
3 1 8333 0 1499414498 42848 0
3 2 8358 0 1499414498 51219 0
4 0 72345 0 1499414498 59433 6
1 3 41718 0 1499414498 67879 4
1 4 8416 0 1499414498 76311 0
3 3 33235 0 1499414498 84469 3
0 0 failed 0 1499414498 84905 9
2 0 failed 0 1499414498 86248 9
3 4 8307 0 1499414498 92788 0

--failures-detailedオプションを使用すると、障害のタイプは次のように時間で報告されます。

3 0 47423 0 1499414498 34501 3
3 1 8333 0 1499414498 42848 0
3 2 8358 0 1499414498 51219 0
4 0 72345 0 1499414498 59433 6
1 3 41718 0 1499414498 67879 4
1 4 8416 0 1499414498 76311 0
3 3 33235 0 1499414498 84469 3
0 0 serialization 0 1499414498 84905 9
2 0 serialization 0 1499414498 86248 9
3 4 8307 0 1499414498 92788 0

大量のトランザクションを処理することができるハードウェアで長時間試験を実行する場合、ログファイルは非常に大きくなる可能性があります。 --sampling-rateオプションを使用して、トランザクションのランダムなサンプルだけをログに記録することができます。

ログ処理の集約

--aggregate-intervalオプションを使用すると、ログファイルに異なるフォーマットが使用されます。 各ログ行は1つの集約間隔を記述します。 このログ行には、スペースで区切られた次のフィールドが含まれます:

interval_start

間隔の開始時刻(Unixエポックタイムスタンプ)

num_transactions

間隔内のトランザクション数

sum_latency

トランザクション待ち時間の合計

sum_latency_2

トランザクション待ち時間の平方和

min_latency

最小トランザクション待ち時間

max_latency

最大トランザクション待ち時間

sum_lag

トランザクション開始遅延の合計(--rateが指定されていない場合は0)

sum_lag_2

トランザクション開始遅延の平方和(--rateが指定されていない場合は0)

min_lag

最小トランザクション開始遅延(--rateが指定されていない場合は0)

max_lag

最大トランザクション開始遅延(--rateが指定されていない場合は0)

skipped

開始が遅すぎたためにスキップされたトランザクションの数(--rate--latency-limitが指定されていない場合は0)

retried

再試行されたトランザクションの数(--max-triesが1でない場合は0)

retries

直列化エラーまたはデッドロックエラー後の再試行回数 (--max-triesが1でない場合は0)

serialization_failures

直列化エラーが発生し、その後再試行されなかったトランザクションの数(--failures-detailedが指定されていない場合は0)

deadlock_failures

デッドロックエラーが発生し、その後再試行されなかったトランザクションの数(--failures-detailedが指定されていない場合は0)

以下に、これらのオプションで生成された出力例を示します。

pgbench --aggregate-interval=10 --time=20 --client=10 --log --rate=1000 --latency-limit=10 --failures-detailed --max-tries=10 test

1650260552 5178 26171317 177284491527 1136 44462 2647617 7321113867 0 9866 64 7564 28340 4148 0
1650260562 4808 25573984 220121792172 1171 62083 3037380 9666800914 0 9998 598 7392 26621 4527 0

通常の(集約されていない)ログフォーマットは、各トランザクションについてどのスクリプトファイルが使用されたかを示しますが、集約されたログにはそれがないことに注意してください。 このためスクリプト単位のデータが必要な場合は、自身でデータを集約する必要があります。

文ごとの報告

-rオプションを使用すると、pgbenchは文ごとに次の統計情報を収集します。

レポートに再試行統計情報が表示されるのは、--max-triesオプションが1に等しくない場合だけです。

すべての値は、各クライアントによって実行される文ごとに計算され、ベンチマークが終了した後に報告されます。

デフォルトのスクリプトの場合、出力は次のようになります。

starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
maximum number of tries: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
number of failed transactions: 0 (0.000%)
number of transactions above the 50.0 ms latency limit: 1311/10000 (13.110 %)
latency average = 28.488 ms
latency stddev = 21.009 ms
initial connection time = 69.068 ms
tps = 346.224794 (without initial connection time)
statement latencies in milliseconds and failures:
   0.012  0  \set aid random(1, 100000 * :scale)
   0.002  0  \set bid random(1, 1 * :scale)
   0.002  0  \set tid random(1, 10 * :scale)
   0.002  0  \set delta random(-5000, 5000)
   0.319  0  BEGIN;
   0.834  0  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
   0.641  0  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
  11.126  0  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
  12.961  0  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
   0.634  0  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
   1.957  0  END;

デフォルトトランザクション分離レベルにシリアライザブルを使用したデフォルトスクリプトの別の出力例(PGOPTIONS='-c default_transaction_isolation=serializable'pgbench.):

starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
maximum number of tries: 10
number of transactions per client: 1000
number of transactions actually processed: 6317/10000
number of failed transactions: 3683 (36.830%)
number of transactions retried: 7667 (76.670%)
total number of retries: 45339
number of transactions above the 50.0 ms latency limit: 106/6317 (1.678 %)
latency average = 17.016 ms
latency stddev = 13.283 ms
initial connection time = 45.017 ms
tps = 186.792667 (without initial connection time)
statement latencies in milliseconds, failures and retries:
  0.006     0      0  \set aid random(1, 100000 * :scale)
  0.001     0      0  \set bid random(1, 1 * :scale)
  0.001     0      0  \set tid random(1, 10 * :scale)
  0.001     0      0  \set delta random(-5000, 5000)
  0.385     0      0  BEGIN;
  0.773     0      1  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
  0.624     0      0  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
  1.098   320   3762  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
  0.582  3363  41576  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
  0.465     0      0  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
  1.933     0      0  END;

複数のスクリプトファイルが定義された場合、すべての統計処理はそれぞれのスクリプトファイル毎に分けて報告されます。

文ごとのレイテンシを計算するために必要となる、追加のタイミング情報を収集することは、オーバーヘッドが加わることに注意してください。 これは平均実行速度を遅くし、計測TPSを小さくするでしょう。 低下量はプラットフォームとハードウェアに依存して著しく変わります。 レイテンシの報告を有効にする、有効にしないで平均TPS値を比較することは、タイミング・オーバーヘッドが顕著かどうかを測定するには良い方法です。

直列化の失敗/デッドロック再試行

pgbenchの実行時に発生する主なエラーには以下の3種類があります。

  • メインプログラムのエラーです。 これらは最も深刻で、常にpgbenchを即座に終了し、対応するエラーメッセージが表示されます。 これらのエラーには以下のようなものがあります:

    • pgbenchの先頭のエラー(例えば無効なオプション値)。

    • 初期化モードでエラーが発生する(例えば、組み込みスクリプト用のテーブルを作成するクエリが失敗する)。

    • スレッドを開始する前のエラー(データベースサーバに接続できない、メタコマンドの構文エラー、スレッド作成の失敗など)。

    • 内部pgbenchエラーです(決して発生しないはずです…)。

  • スレッドがクライアントを管理するときのエラー(クライアントがデータベースサーバへの接続を開始できなかった/クライアントをデータベースサーバに接続するためのソケットが無効になったなど)。 このような場合、このスレッドのすべてのクライアントは停止し、他のスレッドは作業を継続します。

  • 直接的なクライアントエラーです。 内部pgbenchエラーの場合にのみpgbenchを即座に終了し、対応するエラーメッセージが表示されます(これは決して発生しないはずです…)。 そうでなければ、最悪の場合には、他のクライアントが実行を継続している間に、失敗したクライアントが中断されるだけです(ただし、クライアントエラーの中には、クライアントの中断なしに処理され、別途報告されるものもあります。以下を参照してください)。 この節の後半では、説明されているエラーは直接的なクライアントエラーだけであり、内部pgbenchエラーではないと仮定します。

重大なエラーが発生した場合、クライアントの実行は中断されます。 たとえば、データベースサーバーとの接続が失われた場合や、最後のトランザクションを完了せずにスクリプトの終了に達した場合などです。 また、SQLまたはメタコマンドの実行が直列化エラーまたはデッドロックエラー以外の理由で失敗した場合、クライアントは中断されます。 そうでない場合、SQLコマンドが直列化エラーまたはデッドロックエラーで失敗した場合、クライアントは中断されません。 このような場合、現在のトランザクションがロールバックされます。 これには、クライアント変数がこのトランザクションの実行前の状態に設定されます(1つのトランザクションスクリプトには1つのトランザクションのみが含まれていると仮定されます。詳細はpgbenchで実際に実行される"トランザクション"は何か?を参照してください)。 直列化エラーまたはデッドロックエラーのあるトランザクションは、正常に完了するか、最大試行回数(--max-triesオプションで指定/最大再試行時間(--latency-limitオプションで指定)/ベンチマークの終了(--timeオプションで指定)に達するまで、ロールバック後に繰り返されます。 最後の試運転が失敗した場合、このトランザクションは失敗として報告されますが、クライアントは中断されずに処理を続行します。

注記

--max-triesオプションを指定しない場合、デフォルト値が1であるため、シリアライゼーションエラーまたはデッドロックエラーの後にトランザクションが再試行されることはありません。 試行回数を無制限にし(--max-tries=0)、--latency-limitオプションを使用して、試行の最大時間のみを制限します。 また、--timeオプションを使用して、試行回数を無制限にしてベンチマーク期間を制限することもできます。

複数のトランザクションを含むスクリプトを繰り返す場合は注意が必要です。 スクリプトは常に完全に再試行されるため、成功したトランザクションが複数回実行される可能性があります。

シェルコマンドでトランザクションを繰り返す場合は注意してください。 SQLコマンドの結果とは異なり、\setshellコマンドの変数値を除いて、シェルコマンドの結果はロールバックされません。

成功したトランザクションの待機時間には、ロールバックおよび再試行によるトランザクションの実行時間全体が含まれます。 待機時間は、成功したトランザクションおよびコマンドについてのみ測定され、失敗したトランザクションまたはコマンドについては測定されません。

メインレポートには、失敗したトランザクションの数が含まれます。 --max-triesオプションが1以外の場合、メインレポートには再試行に関する統計(再試行されたトランザクションの合計数と再試行の合計数)も含まれます。 スクリプト単位のレポートは、メインレポートからこれらのフィールドをすべて継承します。 文単位のレポートには、--max-triesオプションが1以外の場合にのみ再試行の統計が表示されます。

トランザクションごとおよび集約ログ、メインレポートおよびスクリプトごとのレポートで障害を基本タイプ別にグループ化する場合は、--failures-detailedオプションを使用します。 また、すべてのエラーおよび障害(再試行しない場合のエラー)をタイプ別に区別する場合は、--verbose-errorsオプションを使用します。 これには、直列化エラー/デッドロック障害でどの再試行制限を超えたか、どの程度超えたかなどが含まれます。

テーブルアクセスメソッド

pgbenchテーブルにはテーブルアクセスメソッドを指定できます。 環境変数PGOPTIONSは、コマンドライン経由でPostgreSQLに渡されるデータベース設定オプションを指定します(20.1.4を参照してください)。 例えば、pgbenchが作成するテーブル用のwuzzaと呼ばれる架空のデフォルトテーブルアクセスメソッドは、次のように指定できます。

PGOPTIONS='-c default_table_access_method=wuzza'

優れた実践

まったく無意味な数値を生み出すようにpgbenchを使用することは非常に簡単です。 以下に有意な結果を生み出す手助けとなるガイドラインをいくつか示します。

まず第一に、数秒で終わる試験を決して信用しないでください。 -tまたは-Tオプションを使って、雑音を取り除くために、少なくとも数分試験にかかるようにしてください。 再現可能な数値を得るために数時間必要になる場合もあります。 数回試験を繰り返し、数値が再現できるかどうか確認することを勧めます。

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

デフォルトの試験シナリオはまた、テーブルを初期化してからの経過時間に非常に敏感です。 テーブル内の不要行や不要空間の累積により結果が変わります。 結果を理解するためには、更新された行数とバキューム時期を把握する必要があります。 自動バキュームが有効な場合、性能を測定する上で結果は予測できないほど変わる可能性があります。

pgbenchの制限は、多くのクライアントセッションを試験しようとする際にpgbench自身がボトルネックになる可能性があることです。 これは、データベースサーバとは別のマシンでpgbenchを実行することで緩和させることが可能です。 しかし、多少のネットワーク遅延が重要です。 同一データベースサーバに対し複数のクライアントマシンから複数のpgbenchインスタンスを同時に実行することが有用かもしれません。

セキュリティ

安全なスキーマの利用パターンを適用していないデータベースに信頼できないユーザがアクセス可能な場合、そのデータベースでpgbenchを実行しないでください。 pgbenchは修飾していない名前を使っており、またサーチパスを操作していません。