25.2. 統計情報コレクタ

PostgreSQL統計情報コレクタはサーバの活動状況に関する情報を収集し、報告するサブシステムです。 現在、コレクタはテーブルとインデックスへのアクセスをディスクブロックおよび個々の行単位で数えることができます。

また、PostgreSQLは他のサーバプロセスによって現在実行されている問い合わせを正確に決定する機能を持ちます。 これは独立した機能であり、ブロックレベルの統計情報や行レベルの統計情報を収集しているかどうかに関係なく、有効にすることも無効にすることもできます。

25.2.1. 統計情報収集のための設定

統計情報の収集によって問い合わせの実行に少しオーバーヘッドが加わりますので、システムは情報を収集するようにもしないようにも設定することができます。 これは通常はpostgresql.conf内で設定される、設定パラメータによって制御されます (設定パラメータの設定についての詳細は第17章を参照してください)。

統計情報コレクタを全て起動するには、stats_start_collectorパラメータをtrueに設定する必要があります。 これはデフォルトであり、推奨する設定ですが、統計情報に興味がなく、全ての残存するオーバーヘッドを締め出したいのであれば無効にすることもできます (しかしこれによる成果はわずかなものです)。 サーバ実行中にこのオプションを変更することができないことに注意してください。

stats_block_levelstats_row_levelパラメータは、コレクタに実際に送信される情報量を制御し、つまり、実行時に発生するオーバーヘッドの量を決定します。 これらはそれぞれ、サーバプロセスが、ディスクブロックレベルのアクセス統計、行レベルのアクセス統計を追跡し、コレクタに送信するかどうかを決定します。 さらに、これらのパラメータのいずれかが設定されていた場合、トランザクションのコミットやアボートに関するデータベースごとの統計情報も収集されます。

stats_command_stringパラメータにより、すべてのサーバプロセスで現在実行されているコマンドを監視することができます。 この機能を有効にするために統計情報コレクタサブプロセスを起動させる必要はありません。

通常、これらの変数は全てのサーバプロセスに適用できるようにpostgresql.conf内で設定されます。 しかし、SETコマンドを使用して、個別のセッションで有効または無効にすることができます (一般ユーザがその活動を管理者に隠すことを防止するために、スーパーユーザのみがSETを使用してこれらのパラメータを変更することができます)。

注意: stats_block_levelstats_row_levelパラメータはデフォルトでfalseですので、デフォルトの設定では実際には統計情報は何も収集されません。 これらの設定変数のいずれかを有効にすると、統計情報機能により生成される、有用なデータが激増します。 ただし、実行時のオーバヘッドがさらにかかるようになります。

25.2.2. 収集した統計情報の表示

統計情報の収集結果を表示するための、多くの定義済みのビューがあり、表25-1に一覧表示されています。 他にも、基礎的な統計情報関数を使用した独自のビューを構築することもできます。

この統計情報を使用して、現在の活動状況を監視する場合、この情報は即座に更新されないことを認識することが重要です。 個別のサーバプロセスは、待機状態になる直前に、新しいブロックアクセス数と行アクセス数をコレクタに送信します。 ですので、実行中の問い合わせやトランザクションは表示上の総和には影響を与えません。 また、コレクタ自体もおよそPGSTAT_STAT_INTERVAL(サーバ構築時に変更しない限り500)ミリ秒に一度新しい報告を出力します。 ですので、表示上の情報は実際の活動から遅れて表示されます。 しかし、stats_command_stringで収集される現在の問い合わせの情報は常に最新です。

この他の重要なポイントは、いつサーバプロセスが統計情報を表示するように尋ねられるかです。 サーバプロセスは、まずコレクタによって発行された最も最近の報告を取り出します。 そして、現在のトランザクションが終わるまで、全ての統計情報ビューと関数においてこのスナップショットを使用し続けます。 ですから、現在のトランザクションを続けている間、統計情報は変更されません。 同様に、全プロセスの現在の問い合わせに関する情報も、そうした情報がトランザクションで最初に要求された時に収集され、そのトランザクションの間同じ情報が表示されます。 これはバグではなく、特徴です。 なぜなら、これにより、知らない間に値が変更することを考慮することなく、統計情報に対して複数の問い合わせを実行し、その結果を相関することができるからです。 しかし、各問い合わせで新しい結果を取り出したい場合は、確実にトランザクションブロックの外側でその問い合わせを行ってください。

表 25-1. 標準統計情報ビュー

ビュー名説明
pg_stat_activityサーバプロセス当たり1行の形で、データベースのOID、データベース名、プロセスID、ユーザのOID、ユーザ名、現在の問い合わせ、問い合わせの待機状態、現在の問い合わせの実行開始時刻、プロセス開始時刻、クライアントアドレスとポート番号を表示します。 現在の問い合わせについてのデータを報告する列はstats_command_stringパラメータが有効な場合に表示されます。 さらに、その列は、ビューを確認するユーザがスーパーユーザ、あるいは報告対象プロセスを所有するユーザと同じである場合にのみ参照可能です。
pg_stat_databaseデータベース当たり1行の形で、データベースのOID、データベース名、そのデータベースに接続する活動中のサーバプロセス数、そのデータベース中でコミットされたトランザクションの総数、ロールバックされたトランザクションの総数、読み取られたディスクブロックの総数、バッファヒット(つまり、バッファキャッシュに対象とするブロックが存在するために防止されたブロック読み取り要求)の総数を表示します。
pg_stat_all_tables現在のデータベース内の各テーブル(TOASTテーブルを含みます)に関する、テーブルのOID、スキーマおよびテーブル名、開始されたシーケンシャルスキャン数、シーケンシャルスキャンで取り出された実際の行数、(そのテーブルに属するすべてのインデックスに対して)開始されたインデックススキャン数、インデックススキャンで取り出された実際の行数、挿入、更新、削除された行数、手作業によってそのテーブルがバキュームされた前回の時刻、自動バキュームデーモンによりバキュームされた前回の時刻、手作業によって解析された前回の時刻、自動バキュームデーモンにより解析された前回の時刻。。
pg_stat_sys_tablesシステムテーブルのみが表示される点を除き、pg_stat_all_tablesと同じです。
pg_stat_user_tablesユーザテーブルのみが表示される点を除き、pg_stat_all_tablesと同じです。
pg_stat_all_indexes現在のデータベース内の各インデックスに関する、テーブルとインデックスのOID、スキーマ、テーブルとインデックスの名前、開始されたインデックススキャン数、インデックススキャンによって読み取られたインデックス項目数、インデックスを使用した単純なインデックススキャンで取り出された実際のテーブル行の数。
pg_stat_sys_indexesシステムテーブルのインデックスのみが表示される点を除き、pg_stat_all_indexesと同じです。
pg_stat_user_indexesユーザテーブルのインデックスのみが表示される点を除き、pg_stat_all_indexesと同じです。
pg_statio_all_tables現在のデータベース内の各テーブル(TOASTテーブルを含みます)に関する、テーブルのOID、スキーマとテーブル名、そのテーブルから読み取られたディスクブロックの総数、バッファヒット数、そのテーブルに関する全てのインデックスから読み取られたディスクブロック数とバッファヒット数、(存在する場合)そのテーブルの補助的なTOASTテーブルから読み取られたディスクブロック数とバッファヒット数、TOASTテーブルのインデックスから読み取られたディスクブロック数とバッファヒット数。
pg_statio_sys_tablesシステムテーブルのみが表示される点を除き、pg_statio_all_tablesと同じです。
pg_statio_user_tablesユーザテーブルのみが表示される点を除き、pg_statio_all_tablesと同じです。
pg_statio_all_indexes現在のデータベース内の各インデックスに関する、テーブルとインデックスのOID、スキーマ、テーブルおよびインデックスの名前、そのインデックスから読み取られたディスクブロック数とバッファヒット数。
pg_statio_sys_indexesシステムテーブルのインデックスのみが表示される点を除き、pg_statio_all_indexes と同じです。
pg_statio_user_indexesユーザテーブルのインデックスのみが表示される点を除き、pg_statio_all_indexesと同じです。
pg_statio_all_sequences現在のデータベース内の各シーケンスオブジェクトに関する、シーケンスのOID、スキーマとシーケンスの名前、そのシーケンスから読み取られたディスクブロック数とバッファヒット数。
pg_statio_sys_sequencesシステムシーケンスのみが表示される点を除き、pg_statio_all_sequencesと同じです (現時点では、システムシーケンスは定義されていませんので、このビューは常に空です)。
pg_statio_user_sequencesユーザシーケンスのみが表示される点を除き、pg_statio_all_sequencesと同じです。

インデックス単位の統計情報は、どのインデックスが使用され、どの程度効果があるのかを評価する際に、特に有用です。

PostgreSQL 8.1から、インデックスを直接的、または"ビットマップスキャン"経由で使用することができます。 ビットマップスキャンでは、複数のインデックスの出力をANDまたはOR規則を使って組み合わせることができます。 そのため、ビットマップスキャンが使用されると、個々のヒープ行の取り出しと特定のインデックスとを関連付けることは困難です。 したがって、ビットマップスキャンは使用したインデックスに関するpg_stat_all_indexes.idx_tup_readの数を増やします。 さらに、そのテーブルに関するpg_stat_all_tables.idx_tup_fetchの数も増やします。 しかし、pg_stat_all_indexes.idx_tup_fetchを変更しません。

注意: PostgreSQL 8.1より前では、idx_tup_read の値とidx_tup_fetchの値は基本的には常に同じでした。 idx_tup_readはインデックスから取り出したインデックス項目数を数え、一方でidx_tup_fetchはテーブルから取り出した有効な行数を数えますので、ビットマップスキャンを考慮しなくても、この2つの値が異なることがあり得るようになりました。 インデックスを使用して取り出した行に無効または未コミットの行があると、後者は少なくなります。

pg_statio_ビューは主に、バッファキャッシュの効率を評価する際に有用です。 実ディスク読み取りの数がバッファヒットの数よりもかなり少ないのであれば、そのキャッシュはカーネル呼び出しを行うことなく、ほとんどの読み取り要求を満足させています。 しかし、PostgreSQLバッファキャッシュに存在しないデータはカーネルのI/Oキャッシュにある可能性があり、そのため、物理的な読み取りを行うことなく取り出される可能性があるというPostgreSQLのディスクI/Oの取り扱いのため、これらの統計情報は、完全な論拠を提供しません。 PostgreSQLのI/O動作に関するより詳細な情報を入手したいのであれば、PostgreSQL統計情報コレクタとカーネルのI/Oの取り扱いの監視を行うオペレーティングシステムユーティリティを組み合わせることを勧めます。

統計情報を参照する他の方法は、上述の標準ビュー同様に、基礎的な統計情報アクセス関数を使用した問い合わせを作成することで設定することができます。 これらの関数は表25-2にリストされています。 データベースごとのアクセス関数は、どのデータベースに対して報告するのかを識別するためにデータベースのOIDを受け付けます。 テーブルごと、インデックスごとの関数はテーブルの、もしくはインデックスのOIDを受け付けます (この関数を使用して参照できるテーブルとインデックスは現在のデータベース内のものだけであることに注意してください)。 サーバプロセスごとのアクセス関数はサーバプロセスID番号を受け付けます。 取り得る範囲は1から現時点で活動中のサーバプロセスの数までです。

表 25-2. 統計情報アクセス関数

関数戻り値の型説明
pg_stat_get_db_numbackends(oid)integerデータベース内で活動中のサーバ数。
pg_stat_get_db_xact_commit(oid)bigintデータベース内でコミットされたトランザクション。
pg_stat_get_db_xact_rollback(oid)bigintデータベース内でロールバックされたトランザクション。
pg_stat_get_db_blocks_fetched(oid)bigintデータベースに関する、ディスクブロック抽出要求数。
pg_stat_get_db_blocks_hit(oid)bigintデータベースに関する、ディスクブロック要求の内キャッシュに存在した数。
pg_stat_get_numscans(oid)bigint引数がテーブルの場合、シーケンシャルスキャンの実行回数。 引数がインデックスの場合インデックススキャンの実行回数。
pg_stat_get_tuples_returned(oid)bigint引数がテーブルの場合、シーケンシャルスキャンによって読み取られた行数。 引数がインデックスの場合、返されたインデックス項目数。
pg_stat_get_tuples_fetched(oid)bigint引数がテーブルの場合、ビットマップスキャンで抽出されたテーブル行の数。 引数がインデックスの場合、このインデックスを使用した単純なインデックススキャンで抽出された、テーブル行の数。
pg_stat_get_tuples_inserted(oid)bigintテーブルに挿入された行数。
pg_stat_get_tuples_updated(oid)bigintテーブルで更新された行数。
pg_stat_get_tuples_deleted(oid)bigintテーブルで削除された行数。
pg_stat_get_blocks_fetched(oid)bigintテーブルまたはインデックスに関する、ディスクブロック抽出要求数。
pg_stat_get_blocks_hit(oid)bigintテーブルまたはインデックスに関する、ディスクブロック抽出要求の内キャッシュ内に存在した数。
pg_stat_get_last_vacuum_time(oid)timestamptzテーブルに対してユーザが行ったバキュームの最終時刻。
pg_stat_get_last_autovacuum_time(oid)timestamptzテーブルに対して自動バキュームデーモンが行ったバキュームの最終時刻。
pg_stat_get_last_analyze_time(oid)timestamptzテーブルに対してユーザが行った解析の最終時刻。
pg_stat_get_last_autoanalyze_time(oid)timestamptzテーブルに対して自動バキュームデーモンが行った解析の最終時刻。
pg_stat_get_backend_idset()setof integer現在活動中のサーバプロセス数のセット(1から活動中のサーバプロセス数までの間で) 以下の使用例を参照してください。
pg_backend_pid()integer現在のセッションに接続するサーバプロセスのプロセスID。
pg_stat_get_backend_pid(integer)integer指定されたサーバプロセスのプロセスID。
pg_stat_get_backend_dbid(integer)oid指定されたサーバプロセスのデータベースID。
pg_stat_get_backend_userid(integer)oid指定されたサーバプロセスのユーザID。
pg_stat_get_backend_activity(integer)text指定されたサーバプロセスの現在の問い合わせ。 ただし、現在のユーザがスーパーユーザの場合、または問い合わせ先セッションのユーザの同一の場合(かつ、stats_command_stringが有効の場合)のみです。
pg_stat_get_backend_waiting(integer)boolean指定されたサーバプロセスがロック待ち状態の場合に真です。 しかし、現在のユーザがスーパーユーザの場合、または、問い合わせを行ったユーザと同一の場合(かつ、stats_command_stringが有効の場合)に限ります。
pg_stat_get_backend_activity_start(integer)timestamp with time zone指定されたサーバプロセスが実行中の問い合わせが開始した時刻 ただし、現在のユーザがスーパーユーザの場合、または問い合わせ先セッションのユーザの同一の場合(かつ、stats_command_stringが有効の場合)のみです。
pg_stat_get_backend_start(integer)timestamp with time zone指定されたサーバプロセスが開始した時刻。 現在のユーザがスーパーユーザまたは問い合わせを行っているセッションユーザと同じでない場合はNULL。
pg_stat_get_backend_client_addr(integer)inet指定されたサーバプロセスに接続するクライアントのIPアドレス。 Unixドメインソケット経由の接続の場合はNULL。 また、現在のユーザがスーパーユーザまたは問い合わせを行っているセッションユーザと同じでない場合もNULL。
pg_stat_get_backend_client_port(integer)integer指定されたサーバプロセスに接続するクライアントのIPポート番号。 Unixドメインソケット経由の接続の場合は-1。 現在のユーザがスーパーユーザまたは問い合わせを行っているセッションユーザと同じでない場合はNULL。
pg_stat_reset()booleanすべてのブロックレベルまたは行レベルの統計情報をゼロに戻します。

注意: blocks_fetchedからblocks_hitを引くと、そのテーブル、インデックス、データベースに対して発行されたカーネルのread()コール数がわかります。 しかし、実際の物理的な読み取り数は、カーネルレベルのバッファ処理のために通常これより小さくなります。

pg_stat_get_backend_idset関数は、活動中のサーバプロセスそれぞれについて1行を作成する簡便な方法を提供します。 例えば、全てのサーバプロセスのPIDと現在の問い合わせを表示するには、以下を行います。

SELECT pg_stat_get_backend_pid(s.backendid) AS procpid,
       pg_stat_get_backend_activity(s.backendid) AS current_query
    FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;