pgbench — PostgreSQLに対してベンチマーク試験を行う
pgbench
-i
[option
...] [dbname
]
pgbench
[option
...] [dbname
]
pgbenchはPostgreSQL上でベンチマーク試験を行う単純なプログラムです。
これは同一のSQLコマンドの並びを何度も実行します。複数の同時実行データベースセッションで実行することもできます。
そして、トランザクションの速度(1秒当たりのトランザクション数)の平均を計算します。
デフォルトでpgbenchは、1トランザクション当たり5つのSELECT
、UPDATE
、INSERT
コマンドを含むおおよそTPC-Bに基いたシナリオを試験します。
しかし、独自のトランザクションスクリプトファイルを作成することで他の試験ケースを簡単に実行することができます。
pgbenchの典型的な出力を以下に示します。
transaction type: <builtin: 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は以下の初期化用のコマンドライン引数を受け付けます。
-i
--initialize
初期化モードを呼び出すために必要です。
-I init_steps
--init-steps=init_steps
標準の初期化ステップの内、選択したものだけを実行します。
init_steps
では、各ステップ毎に1文字を使って、実行する初期化ステップを指定します。
各ステップは指定した順で実行されます。
デフォルトはdtgvp
です。
有効なステップは以下の通りです。
d
(Drop)既存のpgbenchのテーブルを全て削除します。
t
(create Tables)
標準のpgbenchシナリオで使われるテーブル、すなわちpgbench_accounts
、pgbench_branches
、pgbench_history
およびpgbench_tellers
を作成します。
g
またはG
(Generate data, クライアント側、またはサーバ側)データを生成し、既存データを置き換えて、標準の各テーブルに読み込みます。
g
(クライアント側データ生成)は、データはpgbench
クライアントで生成されてからサーバに送られます。
これはCOPY
でクライアント/サーバの帯域を大きく使います。
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
指定したフィルファクタでpgbench_accounts
、pgbench_tellers
、pgbench_branches
テーブルを作成します。
デフォルトは100です。
-n
--no-vacuum
初期化でバキュームを実行しません。
(このオプションは-I
で指定されていたとしても初期化ステップv
を抑止します。)
-q
--quiet
ログ処理を、5秒に1つの進行メッセージのみを生成する静寂モードに切り替えます。 デフォルトのログ処理では、100,000行毎にメッセージを1つ出力し、(特に優れたハードウェアでは)1秒当たりに多くのメッセージを出力します。
-I
の中でG
が指定されていれば、この設定は影響しません。
-s
scale_factor
--scale=
scale_factor
この倍率で生成される行数を積算します。
例えば、-s 100
は pgbench_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]
指定の組み込みスクリプトを実行されたスクリプトのリストに追加します。
オプションで@
の後に整数のweight(重み)をつけることで、そのスクリプトが選ばれる確率を調整することができます。
指定しなかった場合は1に設定されます。
利用可能な組み込みのスクリプトは、tpcb-like
、simple-update
、select-only
です。
組み込みの名前の曖昧な接頭辞も受け付けられます。
特別な名前list
を使うと、組み込みスクリプトのリストを表示して、即座に終了します。
-c
clients
--client=
clients
模擬するクライアント数、つまり、同時に実行されるデータベースセッション数です。 デフォルトは1です。
-C
--connect
各クライアントセッションが一度だけ接続を確立するのではなく、各トランザクションが新しい接続を確立します。 これは接続オーバーヘッドを測定する場合に有用です。
-d
--debug
デバッグ用出力を表示します。
-D
varname
=
value
--define=
varname
=
value
独自スクリプト(後述)で使用される変数を定義します。
複数の-D
オプションを使用することができます。
-f
filename[@weight]
--file=
filename[@weight]
filename
から読み取ったトランザクションスクリプトを実行されたスクリプトのリストに追加します。
オプションで@
の後に整数のweight(重み)をつけることで、そのテストが選ばれる確率を調整することができます。
詳細は後で説明します。
-j
threads
--jobs=
threads
pgbench内のワーカスレッド数です。 複数のスレッドを使用することはマルチCPUマシンで有用になります。 クライアントは利用可能なスレッドの間でできる限り均等に分散されます。 デフォルトは1です。
-l
--log
各トランザクションに関する情報をログファイルに書き出します。 後で詳細を説明します。
-L
limit
--latency-limit=
limit
limit
ミリ秒以上続くトランザクションが計数され、別途遅いトランザクションとして報告されます。
制限が使用されると(--rate=...
)、limit
ミリ秒以上遅延がスケジュールされたトランザクションは遅延制限を満たす可能性がないため、サーバに送信されることは決してありません。
これらのトランザクションは計数され、別途スキップされたとして報告されます。
-M
querymode
--protocol=
querymode
サーバへ問い合わせを送信するために使用するプロトコルです。
simple
: 簡易問い合わせプロトコルを使用します。
extended
: 拡張問い合わせプロトコルを使用します。
prepared
: プリペアドステートメントを伴う拡張問い合わせプロトコルを使用します。
prepared
モードでは、pgbenchは問い合わせの2回目の繰り返しからは構文解析結果を再利用しますので、pgbenchは他のモードよりも速く動作します。
デフォルトは簡易問い合わせプロトコルです。 (詳しい情報は第52章を参照してください)
-n
--no-vacuum
試験を実行する前にバキュームを行いません。
pgbench_accounts
、pgbench_branches
、pgbench_history
、
pgbench_tellers
標準テーブルを含まない独自試験シナリオを実行する場合、このオプションは必要です。
-N
--skip-some-updates
組み込みのsimple-update(単純な更新)のスクリプトを実行します。
-b simple-update
の短縮形です。
-P
sec
--progress=
sec
sec
秒毎の進捗レポートを表示します。
レポートには起動からの経過時間、前回レポート時からのTPS、前回レポート時からのトランザクションの平均待ち時間、標準偏差を含んでいます。
(-R
)オプションによる制限下では、待ち時間はトランザクションの実開始時間ではなく、予定開始時間で算出されていますので、平均予定遅延時間が含まれています。
-r
--report-latencies
ベンチマーク完了後の各コマンドにおけるステートメント毎の平均レイテンシ(クライアントから見た実行時間)を報告します。詳しくは下を参照してください。
-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
もなければ、pgbenchはpgbench_tellers
とpgbench_branches
テーブルをバキュームし、pgbench_history
内のデータをすべて消去します。
--aggregate-interval=seconds
集約間隔の長さ(秒単位)です。
これは-l
と一緒でのみ使用できます。
このオプションを付けると、ログには以下で説明するような指定間隔単位の要約が含まれます。
--log-prefix=prefix
--log
により作成されるログファイルのファイル名の先頭につける文字列を設定します。
デフォルトはpgbench_log
です。
--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
の実際のコードを標準エラーに出力し、即座に終了します。
pgbenchは接続パラメータとして以下の共通コマンドライン引数も受け付けます。
-h
hostname
--host=
hostname
データベースサーバのホスト名
-p
port
--port=
port
データベースサーバのポート番号
-U
login
--username=
login
接続ユーザ名
-V
--version
pgbenchのバージョンを表示し、終了します。
-?
--help
pgbenchのコマンドライン引数の説明を表示し、終了します。
実行に成功すればステータス0で終了します。 終了ステータス1は、無効なコマンドラインオプションのような静的な問題を示します。 データベースエラーやスクリプトでの問題などの実行中のエラーは終了ステータス2になります。 後者の場合、pgbenchは部分的な結果を表示します。
PGHOST
PGPORT
PGUSER
デフォルトの接続パラメータです。
このユーティリティは、他のほとんどのPostgreSQLユーティリティと同様、libpqでサポートされる環境変数を使用します(33.14を参照してください)。
環境変数PG_COLOR
は診断メッセージで色を使うかどうかを指定します。
可能な値はalways
、auto
、never
です。
pgbenchは指定したリストからランダムに選択したテストスクリプトを実行します。
これには-b
の組み込みスクリプトと-f
のユーザ定義カスタムスクリプトが含まれます。
各スクリプトには@
の後に指定される相対的な重みを与えることができ、それが選ばれる確率を変更することができます。
デフォルトの重みは1
です。
重みが0
のスクリプトは無視されます。
デフォルトの組み込みトランザクションスクリプト(-b tpcb-like
とすることでも実行されます)は、aid
、tid
、bid
、delta
からランダムに選択され、トランザクション毎に7つのコマンドを発行します。
このシナリオはTPC-Bベンチマークに示唆を受けたものですが、実際にはTPC-Bではないので、この名前になっています。
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;
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行で書き、終わりにセミコロンを付けるようにしてください。
スクリプトファイル向けの簡単な変数置換機能があります。
変数名は文字(非ラテン文字を含む)、数字およびアンダースコアで構成されていなければなりません。
上で説明したように変数を-D
コマンドラインオプションで設定することができます。
また、後で説明するようにメタコマンドで設定することもできます。
-D
コマンドラインオプションで設定された変数の他に、表 273に記載されているように、自動的に設定される変数がいくつかあります。
-D
を使ってこれらの変数に設定された値は、自動設定の値より優先されます。
一度設定すると、変数の値は、:
variablename
と書かれてSQLコマンドに挿入されます。
1つ以上のクライアントセッションが実行される場合、セッション毎に独自の変数群を持ちます。
pgbenchは1つの文内で255個までの変数の利用をサポートします。
表273 pgbench Automatic Variables
変数 | 説明 |
---|---|
client_id | クライアントセッションを識別する一意の数値(ゼロから始まる) |
default_seed | デフォルトでハッシュ関数で使われるシード |
random_seed | ランダムジェネレータのシード(-D で上書きされていないなら) |
scale | 現在のスケールファクタ |
スクリプトファイルのメタコマンドはバックスラッシュ(\
)から始まり、通常は行末まで続きますが、バックスラッシュと改行を書くことで、追加の行に続けることができます。
メタコマンドへの引数は空白文字で区切られます。
以下のメタコマンドがサポートされています。
\gset [prefix
]
\aset [prefix
]
このコマンドは、終了を意味するセミコロン(;
)の置き換えで、SQL問い合わせを終えるために使われます。
\gset
コマンドが使われると、それまでのSQL問い合わせは1行を返すものと期待され、その行の列は列名にちなんだ名前の変数に格納されます。prefix
が指定されていれば、変数名の前に付きます。
\aset
コマンドが使われると、(\;
で分けられた)すべての結合したSQL問い合わせは、その列が列名にちなんだ名前の変数に格納されます。prefix
が指定されていれば、変数名の前に付きます。
問い合わせが行を返さなければ、割り当ては行なわれませんので、これを検出するために変数の存在をテストできます。
問い合わせが2行以上返した場合、最後の値が保持されます。
以下の例は、最初の問い合わせからの最終的な口座残高を変数abalance
に入れ、変数p_two
とp_three
を3番目の問い合わせからの整数で埋めます。
2番目の問い合わせの結果は捨てられます。
最後の2つの結合した問い合わせの結果は、変数four
とfive
に格納されます。
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
定数、真理値定数のTRUE
とFALSE
、5432
のような整数の定数、3.14159
のような倍精度実数の定数、変数を参照する :
variablename
、通常のSQLの優先度と結合規則での演算子、関数呼び出し、SQLのCASE
一般条件式および括弧を含むことができます。
関数と大部分の演算子はNULL
入力にNULL
を返します。
条件の用途では非ゼロの数値はTRUE
、ゼロ数値とNULL
はFALSE
です。
大きすぎるもしくは小さすぎる整数や倍精度実数の定数は、整数算術演算子(+
、-
、*
、/
)と同様にオーバーフローエラーになります。
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
表 274に載っている算術、ビットごと、比較、論理の演算子はpgbenchに組み込まれていて、\set
の式で使用できます。
演算子は優先度の低い順に載っています。
注意書きがある場合を除いて、2つの数値を取る演算子は、入力の片方が倍精度実数であれば倍精度実数の値を結果とし、そうでなければ整数の結果になります。
表274 pgbenchの演算子
演算子 説明 例 |
---|
論理OR
|
論理AND
|
論理NOT
|
ブール値のテスト
|
NULLであるかのテスト
|
等価
|
不等
|
不等
|
より小さい
|
以下
|
より大きい
|
以上
|
ビット毎のOR
|
ビット毎のXOR
|
ビット毎のAND
|
ビット毎のNOT
|
ビット毎の左シフト
|
ビット毎の右シフト
|
加算
|
減算
|
乗算
|
除算(入力が両方とも整数であれば、結果は0に向けて丸められる)
|
剰余(余り)
|
符号反転
|
表 275に示す関数はpgbenchに組み込まれており、\set
に現れる式の中で使うことができます。
表275 pgbenchの関数
関数 説明 例 |
---|
絶対値
|
引数をstderrに出力し、引数を返す。
|
倍精度実数にキャストする。
|
指数(
|
引数の中で最大の値を選択する。
|
これは
|
FNV-1aハッシュを計算する。
|
MurmurHash2ハッシュを計算する。
|
整数にキャストする。
|
引数の中で最小の値を選択する。
|
自然対数
|
剰余(余り)
|
πの近似値
|
|
|
|
|
|
平方根
|
random
関数は一様分布を使って値を生成します。
つまり、すべての値は指定された範囲内で同じ確率で発生します。
random_exponential
、random_gaussian
、および、random_zipfian
関数は追加の倍精度実数のパラメータを必要とし、それによって分布の正確な形が決まります。
指数分布では、parameter
が分布を制御します。
急速に減少する指数分布をparameter
で切り捨て、境界範囲内の整数に射影します。
正確には、以下の式に従います。
f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))
これにより、min
とmax
の間(両端を含む)の間の値i
がf(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)
とすると、min
とmax
の間(両端を含む)の値i
が発生する確率はf(i + 0.5) - f(i - 0.5)
になります。
直感的には、parameter
が大きくなれば、間隔の中間に近い値になる確率が高く、また、min
とmax
の境界に近い値になる確率は低くなります。
約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)
は、値1
を2
の約(2/1)**2.5 = 5.66
倍高い頻度で生成し、値2
を3
の約(3/2)**2.5 = 2.76
倍高い頻度で生成し、以下同様に続きます。
pgbenchの実装は「Non-Uniform Random Variate Generation」Luc Devroye(Springer 1986, p. 550-551)に基づいており、parameter
値は[1.001, 1000]の範囲に限定されています。
ハッシュ関数hash
、hash_murmur2
およびhash_fnv1a
は入力値とオプションシードパラメータを受け付けます。
シードが与えられなかった場合、:default_seed
の値が使われます。これは、コマンドライン-D
オプションで設定されない限りランダムに初期化されたものです。
ハッシュ関数はrandom_zipfian
やrandom_exponential
などのランダム関数の分布を散らすのに使用できます。
例えば、以下のpgbenchスクリプトは起こりえる現実世界のソーシャルメディアとブログプラットフォームに対する僅かなアカウントしか過大な負荷をかけないという典型的な負荷をシミュレートします。
\set r random_zipfian(0, 100000000, 1.07) \set k abs(hash(:r)) % 1000000
一部のケースでは、互いに無関係ないくつかの異なる分布が必要で、これは暗黙のシードパラメータが役立ちます。
\set k1 abs(hash(:r, :default_seed + 123)) % 1000000 \set k2 abs(hash(:r, :default_seed + 321)) % 1000000
例えば、組み込みの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_log
、nnn
はpgbenchプロセスのPIDです。
ファイル名の先頭の文字列は--log-prefix
オプションを使って変更することができます。
-j
オプションが2以上で複数のワーカスレッドがある場合、それぞれが独自のログファイルを持つことになります。
最初のワーカは標準的な単一ワーカの場合と同じ名前を持つログファイルを使用します。
他のワーカ用の追加のログファイルは
と命名され、ここでprefix
.nnn
.mmm
mmm
は1から始まる各ワーカの連番です。
ログの書式は以下の通りです。
client_id
transaction_no
time
script_no
time_epoch
time_us
[schedule_lag
]
client_id
はどのクライアントセッションがそのトランザクションを実行したかを示します。
transaction_no
はそのセッションで何個のトランザクションが実行されたかを示します。
time
はトランザクションの合計消費時間をマイクロ秒単位で示します。
script_no
はどのスクリプトファイルが使用されたかを識別するものです(-f
または-b
で複数のスクリプトが指定された場合に有用です)。
time_epoch
/time_us
はトランザクション完了時のUnixエポック時間とマイクロ秒単位のオフセットです(小数秒付きのISO 8601タイムスタンプの作成に適します)。
schedule_lag
フィールドは、マイクロ秒単位のトランザクションの予定開始時刻と実開始時刻の差です。
これは--rate
オプションを使用した時だけ表示されます。
--rate
と--latency-limit
の両方のオプションを使用した時は、スキップされたトランザクションのtime
がskipped
として表示されます。
単一クライアントでの実行で生成されたログファイルの一部を示します。
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つのトランザクションは、開始する前にすでに遅れてしまっているため、スキップされています。
大量のトランザクションを処理することができるハードウェアで長時間試験を実行する場合、ログファイルは非常に大きくなる可能性があります。
--sampling-rate
オプションを使用して、トランザクションのランダムなサンプルだけをログに記録することができます。
--aggregate-interval
オプションを付ける場合、以下のようにログの書式が異なります。
interval_start
num_transactions
sum_latency
sum_latency_2
min_latency
max_latency
[sum_lag
sum_lag_2
min_lag
max_lag
[skipped
] ]
interval_start
はインターバルの開始時刻(Unixエポック時間)です。
num_of_transactions
はインターバル内のトランザクション数です。
latency_sum
はインターバル内のトランザクションレイテンシの総和です。
sum_latency_2
はインターバル内のトランザクションレイテンシの2乗の総和です。
min_latency
はインターバル内の最小レイテンシです。
max_latency
はインターバル内の最大レイテンシです。
これに続くフィールドsum_lag
、sum_lag_2
、min_lag
、max_lag
は--rate
オプションが指定された場合にのみ表示されます。
これらは、各トランザクションが直前のトランザクションの終了を待機しなければならなかった時間、つまりトランザクションの予定開始時刻と実際の開始時刻の差に関する統計を提供します。
一番最後のフィールドskipped
は--latency-limit
オプションも使用されたときにのみ表示されます。
これは開始時刻が遅くなったためにスキップされたトランザクションの数を数えます。
各トランザクションはインターバル内でコミットされた時に数えられます。
いくつか出力例を示します。
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: <builtin: 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 latency average = 15.844 ms latency stddev = 2.715 ms tps = 618.764555 (including connections establishing) tps = 622.977698 (excluding connections establishing) statement latencies in milliseconds: 0.002 \set aid random(1, 100000 * :scale) 0.005 \set bid random(1, 1 * :scale) 0.002 \set tid random(1, 10 * :scale) 0.001 \set delta random(-5000, 5000) 0.326 BEGIN; 0.603 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.454 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 5.528 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 7.335 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.371 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.212 END;
複数のスクリプトファイルが定義された場合、平均値はそれぞれのスクリプトファイル毎に分けて報告されます。
ステートメント毎のレイテンシを計算するために必要となる、追加のタイミング情報を収集することは、オーバーヘッドが加わることに注意してください。 これは平均実行速度を遅くし、計測TPSを小さくするでしょう。 低下量はプラットフォームとハードウェアに依存して著しく変わります。 レイテンシの報告を有効にする、有効にしないで平均TPS値を比較することは、タイミング・オーバーヘッドが顕著かどうかを測定するには良い方法です。
まったく無意味な数値を生み出すようにpgbenchを使用することは非常に簡単です。 以下に有意な結果を生み出す手助けとなるガイドラインをいくつか示します。
まず第一に、数秒で終わる試験を決して信用しないでください。
-t
または-T
オプションを使って、雑音を取り除くために、少なくとも数分試験にかかるようにしてください。
再現可能な数値を得るために数時間必要になる場合もあります。
数回試験を繰り返し、数値が再現できるかどうか確認することを勧めます。
デフォルトのTPC-Bのような試験シナリオでは、初期倍率(-s
)を試験予定のクライアント数(-c
)の最大値と同程度にしなければなりません。
pgbench_branches
テーブルには-s
行しかありません。
また、全トランザクションはその内の1つを更新しようとします。
ですので、-c
値を-s
より大きくすると、他のトランザクションを待機するためにブロックされるトランザクションが多くなることは間違いありません。
デフォルトの試験シナリオはまた、テーブルを初期化してからの経過時間に非常に敏感です。 テーブル内の不要行や不要空間の累積により結果が変わります。 結果を理解するためには、更新された行数とバキューム時期を把握する必要があります。 自動バキュームが有効な場合、性能を測定する上で結果は予測できないほど変わる可能性があります。
pgbenchの制限は、多くのクライアントセッションを試験しようとする際にpgbench自身がボトルネックになる可能性があることです。 これは、データベースサーバとは別のマシンでpgbenchを実行することで緩和させることが可能です。 しかし、多少のネットワーク遅延が重要です。 同一データベースサーバに対し複数のクライアントマシンから複数のpgbenchインスタンスを同時に実行することが有用かもしれません。
安全なスキーマの利用パターンを適用していないデータベースに信頼できないユーザがアクセス可能な場合、そのデータベースでpgbenchを実行しないでください。 pgbenchは修飾していない名前を使っており、またサーチパスを操作していません。