pgbenchはPostgreSQL上でベンチマーク試験を行う単純なプログラムです。 これは同一のSQLコマンドの並びを何度も実行します。複数の同時実行データベースセッションで実行することもできます。 そして、トランザクションの速度(1秒当たりのトランザクション数)の平均を計算します。 デフォルトでpgbenchは、1トランザクション当たり5つのSELECT、UPDATE、INSERTコマンドを含むおおよそTPC-Bに基いたシナリオを試験します。 しかし、独自のトランザクションスクリプトファイルを作成することで他の試験ケースを簡単に実行することができます。
pgbenchの典型的な出力を以下に示します。
transaction type: TPC-B (sort of) scaling factor: 10 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 tps = 85.184871 (including connections establishing) tps = 85.296346 (excluding connections establishing)
最初の6行はいくつかの最重要パラメータの設定を表示しています。 次行が完了トランザクション数と予定トランザクション数です(後者は単なるクライアント数とクライアント毎のトランザクション数の積算結果です。) 実行が完了する前に失敗しない限りこれは等しくなります。 (-Tモードでは、トランザクションの実際の数が表示されます) 最後の2行は、データベースセッションを開始するための時間を含める場合と含めない場合の1秒当たりのトランザクション数を示します。
デフォルトのTPC-Bと似たトランザクション試験では、あらかじめ設定する特定のテーブルが必要です。 これらのテーブルを作成し、データを投入するためには、-i(初期化)オプションを付けてpgbenchを呼び出さなければなりません。 (独自スクリプトを試験する場合、この手順は必要ありません。 しかし代わりに試験に必要な何らかの設定を行わなければならないでしょう。) 初期化は以下のようになります。
pgbench -i [ other-options ] dbname
ここでdbnameは試験用に前もって作成されたデータベースの名前です。 (またデータベースサーバの接続方法を指定するために、-h、-p、-Uが必要になるかもしれません。)
注意 |
pgbench -iは4つのテーブルpgbench_accounts、pgbench_branches、pgbench_history、pgbench_tellersを作成します。 もしあればこうした名前のテーブルは破壊されます。 もし同じ名前のテーブルが存在する場合にはよく注意してください。 |
デフォルトの"倍数"の1では、テーブルは初期状態で以下の行数を含みます。
table # of rows --------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
-s(倍数)オプションを使用して行数を増加させることができます(また、ほとんどの目的ではおそらく増加させるべきです)。 また、-F (フィルファクタ)オプションをここで使用しても構いません。
一度この必要な設定を行った後、以下のように-iを持たないコマンドでベンチマークを行うことができます。
pgbench [ options ] dbname
ほとんどすべての場合、有用な試験とするためにいくつかのオプションが必要になります。 最重要オプションは-c(クライアント数)、-t(トランザクション数)、-T (制限時間)、-f(独自スクリプトファイルの指定)です。 以下の全一覧を参照してください。
以下では、データベース初期化時に使用されるオプション、ベンチマーク実行時に使用されるオプション、どちらの場合でも使われるオプションの3つに分けて説明します。
pgbenchは以下の初期化用のコマンドライン引数を受け付けます。
初期化モードを呼び出すために必要です。
指定したフィルファクタでpgbench_accounts、pgbench_tellers、pgbench_branchesテーブルを作成します。 デフォルトは100です。
初期化の後にバキューム処理を行いません。
ログ処理を、5秒に1つの進行メッセージのみを生成する静寂モードに切り替えます。 デフォルトのログ処理では、10000行毎にメッセージを1つ出力し、(特に優れたハードウェアでは)1秒当たりに多くのメッセージを出力します。
この倍率で生成される行数を積算します。 例えば、-s 100は pgbench_accountsテーブルに10,000,000行を生成することを意味します。 デフォルトは1です。 この倍率が20000以上になると、アカウント識別子の範囲を保持できる程度に大きくなるように、アカウント識別子を保持するために使用される列(aid列)はより大きな整数(bigint)を使用するように切り替わります。
標準テーブル間で外部キー制約を作成します。
デフォルトのテーブル空間ではなく、指定したテーブル空間の中にインデックスを作成します。
デフォルトのテーブル空間ではなく、指定したテーブル空間の中にテーブルを作成します。
永続テーブルではなくログを取らないテーブルとしてテーブルを作成します。
pgbenchは以下のベンチマーク用コマンドライン引数を受け付けます。
模擬するクライアント数、つまり、同時に実行されるデータベースセッション数です。 デフォルトは1です。
各クライアントセッションが一度だけ接続を確立するのではなく、各トランザクションが新しい接続を確立します。 これは接続オーバーヘッドを測定する場合に有用です。
デバッグ用出力を表示します。
独自スクリプト(後述)で使用される変数を定義します。 複数の-Dオプションを使用することができます。
トランザクションスクリプトをfilenameから読み取ります。 詳細は後で説明します。 -N、-S、-fは互いに排他的です。
pgbench内のワーカスレッド数です。 複数のスレッドを使用することはマルチCPUマシンで有用になります。 各スレッドには管理するクライアントセッションを同じ数与えられますので、クライアント数はスレッド数の倍数でなければなりません。 デフォルトは1です。
各トランザクションで費やした時間をログファイルに書き出します。 後で詳細を説明します。
サーバへ問い合わせを送信するために使用するプロトコルです。
simple: 簡易問い合わせプロトコルを使用します。
extended: 拡張問い合わせプロトコルを使用します。
プリペアドステートメントを伴う拡張問い合わせプロトコルを使用します。
デフォルトは簡易問い合わせプロトコルです。 (詳しい情報は第48章を参照してください)
試験を実行する前にバキュームを行いません。 pgbench_accounts、pgbench_branches、pgbench_history、 pgbench_tellers標準テーブルを含まない独自試験シナリオを実行する場合、このオプションは必要です。
pgbench_tellersとpgbench_branchesを更新しません。 これは両テーブル上の重度の更新の競合を防ぎますが、TPC-Bのような試験ケースを行わなくなります。
ベンチマーク完了後の各コマンドにおけるステートメント毎の平均レイテンシ(クライアントから見た実行時間)を報告します。詳しくは下を参照してください。
pgbenchの出力で指定した倍率を報告します。 これは組み込みの試験では必要ありません。 正確な倍率がpgbench_branchesテーブルの行数を数えることで検出されます。 しかし、独自ベンチマーク(-fオプション)を試験している場合、このオプションを使用しない限り、倍率は1として報告されます。
TPC-Bのような試験ではなく読み取りのみのトランザクションを実行します。
各クライアントが実行するトランザクション数です。 デフォルトは10です。
クライアントあたりのトランザクション数を固定で指定するよりも長くテストを実行したい場合、ここに指定した秒数でテストを実行します。 -tと-Tは互いに排他的です。
試験前に4つの標準テーブルすべてをバキュームを行います。 -nも-vもなければ、pgbenchはpgbench_tellersとpgbench_branchesテーブルをバキュームし、pgbench_history内のデータをすべて消去します。
集約間隔の長さ(秒単位)です。 これは-lと一緒でのみ使用される可能性があります。 このオプションを付けると、ログには指定間隔単位の要約(トランザクション数、最大レイテンシ、最小レイテンシ、分散の推定に役に立つ2つの追加フィールド)が含まれます。
現在このオプションはWindowsではサポートされていません。
データをログに書き出す際に使用される、生成されるログの量を減少するためのサンプリング割合です。 このオプションが指定された場合、指定された割合のトランザクションがログに残ります。 1.0はすべてのトランザクションが、0.05はトランザクションの5%のみがログに残ることを意味します。
ログファイルを処理する際にはこのサンプリング割合を考慮することを忘れないでください。 例えば、tps値を計算する際には、比例した数を掛け合わせなければなりません(例:サンプリング割合が0.01の場合実際のtpsの1/100を得るだけです。)
デフォルトのトランザクションスクリプトは、1トランザクションで以下の7コマンドを発行します。
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;
-Nを指定した場合、第4コマンドと第5コマンドはトランザクションに含まれません。 -Sを指定した場合、SELECTのみが発行されます。
pgbenchは、ファイルから読み込んだトランザクションスクリプト(-fオプション)でデフォルトのトランザクションスクリプト(上述)を置き換えて独自のベンチマークシナリオを実行する機能をサポートします。 この場合、"トランザクション"はスクリプトファイルの1回の実行として数えられます。 複数のスクリプトを指定する(複数の-fオプション)ことさえ可能です。 この場合、クライアントセッションが新しいトランザクションを開始する時にランダムにスクリプトの1つが選択されます。
スクリプトファイルの書式は、1行1 SQLコマンドという形で、複数行に跨るSQLコマンドはサポートされません。 空行および--から始まる行は無視されます。 スクリプトファイルの行には、pgbench自身が解釈する"メタコマンド"(後述)も記述することができます。
スクリプトファイル向けの簡単な変数置換機能があります。 上で説明したように変数を-Dコマンドラインオプションで設定することができます。 また、後で説明するようにメタコマンドで設定することもできます。 -Dコマンドラインオプションで設定された変数の他に、scale変数は現在のスケールファクタに設定されます。 一度設定すると、:variablenameと記述することで変数の値はSQLコマンドに挿入されます。 1つ以上のクライアントセッションを実行する時、セッション毎に独自の変数群を持ちます。
スクリプトファイルメタコマンドはバックスラッシュ(\)から始まります。 メタコマンドへの引数は空白文字で区切られます。 以下のメタコマンドがサポートされています。
varname変数を計算された整数値に設定します。 各operandは整数定数か整数値を持つ変数への:variablename参照のいずれかです。 operatorは+、-、*、/を取ることができます。
例
\set ntellers 10 * :scale
varname変数をminからmaxまでの範囲のランダムな整数値に設定します。 各制限は整数定数か整数値を持つ変数への:variablename参照のいずれかです。
例
\setrandom aid 1 :naccounts
スクリプトの実行をマイクロ秒(us)、ミリ秒(ms)、秒(s)単位で指定した間待機させます。 単位を省略した場合、デフォルトは秒です。 numberは整数定数か整数値を持つ変数への:variablename参照のいずれかです。
例
\sleep 10 ms
commandシェルコマンドの結果をvarname変数に設定します。 このコマンドは標準出力を通して整数値を返さなければなりません。
argumentは、テキスト定数または任意の型の変数を参照する:variablenameとすることができます。 コロンから始まるargumentを使用したい場合、argumentの先頭にさらにコロンを付けなければなりません。
例:
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
\setshellと同じですが、結果は無視されます。
例:
\shell command literal_argument :variable ::literal_starting_with_colon
例えば、組込みのTPC-Bのようなトランザクションの完全な定義を示します。
\set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -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は各トランザクションで要した時間をログファイルに書き出します。 ログファイルの名前はpgbench_log.nnnです。 ここでnnnはpgbenchプロセスのPIDです。 -jオプションが2以上の場合、それぞれ独自のログファイルを持つ複数のワーカスレッドが生成されます。 最初のワーカは標準的な単一ワーカの場合と同じ名前を持つログファイルを使用します。 他のワーカ用の追加のログファイルはpgbench_log.nnn.mmmのように命名されます。 ここでmmmは1から始まる各ワーカの連番です。
ログの書式は以下の通りです。
client_id transaction_no time file_no time_epoch time_us
ここでtimeはマイクロ秒単位の総トランザクション処理時間、file_noは使用されたスクリプトファイルを識別するもの(-fにより複数のスクリプトが指定された場合に有用)、time_epoch/time_usはマイクロ秒のオフセットを持つUNIXエポック書式のタイムスタンプ(秒部分付きのISO 8601タイムスタンプの作成に適します)でトランザクションの完了時刻を示します。
以下に出力例を示します。
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
大量のトランザクションを処理することができるハードウェアで長時間試験を実行する場合、ログファイルは非常に大きくなる可能性があります。 --sampling-rateオプションを使用して、トランザクションのランダムなサンプルだけをログに記録することができます。
--aggregate-intervalオプションを付ける場合、以下のようにログの書式が多少異なります。
interval_start num_of_transactions latency_sum latency_2_sum min_latency max_latency
ここで、interval_startは間隔の開始時刻(UNIXエポック書式のタイムスタンプ)、num_of_transactionsは間隔内のトランザクション数、latency_sumはレイテンシの総和(簡単に平均レイテンシを計算できます)です。 続く2つのフィールドは分散推定の際に有用です。 latency_sumはレイテンシの総和であり、latency_2_sumはレイテンシの二乗の総和です。 最後の2つのフィールドは、間隔内の最小レイテンシであるmin_latencyと、間隔内の最大レイテンシであるmax_latencyです。 コミットされた時点でトランザクションは間隔内で考慮されます。
以下に出力例を示します。
1345828501 5601 1542744 483552416 61 2573 1345828503 7884 1979812 565806736 60 1479 1345828505 7208 1979422 567277552 59 1391 1345828507 7685 1980268 569784714 60 1398 1345828509 7073 1979779 573489941 236 1411
通常の(集約されていない)ログファイルには、カスタムスクリプトファイルの目印が含まれますが、集約されたログには含まれません。 このためスクリプトデータ単位が必要な場合は、自身でデータを集約しなければなりません。
-rオプションを付けると、pgbenchは各クライアントにより実行されたトランザクションのステートメント毎の経過時間を収集します。 ベンチマークが終了した後、各値の平均値(各ステートメントのレイテンシと呼びます)が報告されます。
標準スクリプトでは、次のような出力になります。
starting vacuum...end. transaction type: TPC-B (sort of) scaling factor: 1 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 tps = 618.764555 (including connections establishing) tps = 622.977698 (excluding connections establishing) statement latencies in milliseconds: 0.004386 \set nbranches 1 * :scale 0.001343 \set ntellers 10 * :scale 0.001212 \set naccounts 100000 * :scale 0.001310 \setrandom aid 1 :naccounts 0.001073 \setrandom bid 1 :nbranches 0.001005 \setrandom tid 1 :ntellers 0.001078 \setrandom delta -5000 5000 0.326152 BEGIN; 0.603376 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.454643 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 5.528491 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 7.335435 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.371851 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.212976 END;
複数のスクリプトファイルが定義された場合、平均値はそれぞれのスクリプトファイル毎に分けて報告されます。
ステートメント毎のレイテンシを計算するために必要となる、追加のタイミング情報を収集することは、オーバーヘッドが加わることに注意してください。 これは平均実行速度を遅くし、計測TPSを小さくするでしょう。 低下量はプラットフォームとハードウェアに依存して著しく変わります。 レイテンシの報告を有効にする、有効にしないで平均TPS値を比較することは、タイミング・オーバーヘッドが顕著かどうかを測定するには良い方法です。
まったく無意味な数値を生み出すようにpgbenchを使用することは非常に簡単です。 以下に有意な結果を生み出す手助けとなるガイドラインをいくつか示します。
まず第一に、数秒で終わる試験を決して信用しないでください。 -tまたは-Tオプションを使って、雑音を取り除くために、少なくとも数分試験にかかるようにしてください。 再現可能な数値を得るために数時間必要になる場合もあります。 数回試験を繰り返し、数値が再現できるかどうか確認することを勧めます。
デフォルトのTPC-Bのような試験シナリオでは、初期倍率(-s)を試験予定のクライアント数(-c)の最大値と同程度にしなければなりません。 pgbench_branchesテーブルには-s行しかありません。 また、前トランザクションはその内の1つを更新しようとします。 ですので、-c値を-sより大きくすると、他のトランザクションを待機するためにブロックされるトランザクションが多くなることは間違いありません。
デフォルトの試験シナリオはまた、テーブルを初期化してからの経過時間に非常に敏感です。 テーブル内の不要行や不要空間の累積により結果が変わります。 結果を理解するためには、更新された行数とバキューム時期を把握する必要があります。 自動バキュームが有効な場合、性能を測定する上で結果は予測できないほど変わる可能性があります。
pgbenchの制限は、多くのクライアントセッションを試験しようとする際にpgbench自身がボトルネックになる可能性があることです。 これは、データベースサーバとは別のマシンでpgbenchを実行することで緩和させることが可能です。 しかし、多少のネットワーク遅延が重要です。 同一データベースサーバに対し複数のクライアントマシンから複数のpgbenchインスタンスを同時に実行することが有用かもしれません。