他のバージョンの文書 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

51.73. pg_locks

pg_locksビューはデータベースサーバ内でアクティブなプロセスによって保持されたロックに関する情報へのアクセスを提供します。 ロックに関するより詳細な説明は第13章を参照してください。

pg_locksにはロック対象となる進行中のオブジェクト、要求されたロックモード、および関連するプロセス毎に1つの行を持ちます。 ですから、もし複数のプロセスが同じロック対象オブジェクトに対してロックを保持していたりロックを待機している場合には、同じロック対象オブジェクトが何度も出現することがあります。 しかし現在ロックされていないオブジェクトはまったく現れません。

ロック対象オブジェクトには異なる型がいくつか存在します。 リレーション全体(例:テーブル)、リレーションの個別のページ、リレーションの個別のタプル、トランザクションID(仮想と永続の両方のID)、一般的なデータベースオブジェクト(これはpg_descriptionpg_dependと同様にクラスOIDとオブジェクトOIDで識別されます)。 さらに、リレーションを拡張する権利は、別のロック対象オブジェクトとして表現されます。 また勧告的ロックはユーザ定義の意味を持つ複数から形成されるかもしれません。

表51.74 pg_locksの列

名前参照先説明
locktypetext  ロック対象オブジェクトの種類。 relationextendpagetupletransactionidvirtualxidobjectuserlockadvisory
databaseoidpg_database.oidロック対象が存在しているデータベースのOID。対象が共有オブジェクトの場合はゼロ。対象がトランザクションIDである場合はNULL。
relationoidpg_class.oidロックの対象となるリレーションのOID。対象がリレーションではない場合かリレーションの一部である場合はNULL。
pageinteger ロックの対象となるリレーション内のページ番号。対象がタプルもしくはリレーションページではない場合はNULL。
tuplesmallint ページ内のロックの対象となっているタプル番号。対象がタプルではない場合はNULL。
virtualxidtext ロックの対象となるトランザクションの仮想ID。対象が仮想トランザクションIDではない場合はNULL。
transactionidxid ロックの対象となるトランザクションのID。対象がトランザクションIDではない場合はNULL。
classidoidpg_class.oidロックの対象を含むシステムカタログのOID。対象が一般的なデータベースオブジェクトではない場合はNULL。
objidoidany OID columnシステムカタログ内のロックの対象のOID。 対象が一般的なデータベースオブジェクトでない場合はNULL。
objsubidsmallint ロック対象の列番号(classidobjidはテーブル自身を参照します)、その他の一般的なデータベースオブジェクトではゼロ、一般的ではないデータベースオブジェクトではNULLです。
virtualtransactiontext  ロックを保持、もしくは待っている仮想トランザクションID。
pidinteger ロックを保持、もしくは待っているサーバプロセスのプロセスID。 ただしプリペアードトランザクションによりロックが保持されている場合はNULL。
modetext このプロセスで保持または要求するロックモードの名称。 (13.3.1 and 13.2.3参照)
grantedboolean ロックが保持されている場合は真、ロックが待ち状態の場合は偽
fastpathboolean  ファストパス経由でロックが獲得されている場合は真、メインロックテーブル経由で獲得されている場合は偽。

指定されたプロセスにより保持されているロックを表す行内ではgrantedは真です。 偽の場合はこのロックを獲得するため現在プロセスが待機中であることを示しています。 つまり、同じロック対象のオブジェクトに対して何らかの他のプロセスが競合するロックを保持、もしくは待機していることを意味します。 待機中のプロセスはその別のプロセスがロックを解放するまで活動を控えます。 (もしくはデッドロック状態が検出されることになります)。 単一プロセスでは一度に多くても1つのロックを獲得するために待機します。

トランザクションの実行中は常に、サーバプロセスはその仮想トランザクションID上に排他的ロックをかけます。 もしある永続IDがトランザクションに割り当てられる(普通はトランザクションがデータベースの状態を変化させるときのみに発生します)と、トランザクションは終了するまで永続トランザクションIDに対して排他ロックを保持します。 あるトランザクションが他のトランザクションを特定して終了まで待機しなければならないと判断した場合、他とみなしたトランザクションのIDに対し共有ロックを獲得するように試み、目的を達します。 (仮想IDであるか永続IDであるかは、その状況によります)。 これは、他とみなしたトランザクションが完了し、そしてロックを解放した場合のみ成功します。

タプルはロック対象のオブジェクト種類ですが、行レベルロックについての情報はメモリではなく、ディスクに保存されます。 よって行レベルロックは通常、このビューには現れません。 もしプロセスが行レベルロックの待ち状態である場合は、その行ロックを保持している永続トランザクションIDを待つ状態で、そのトランザクションはビューに現れます。

勧告的ロックは、単一のbigint値、または、2つの整数値をキーとして獲得することができます。 bigintの場合は、その上位半分がclassid列内に表示され、残りの下位半分はobjid列内に表示されます。 また、objsubidは1です。 元のbigint値を(classid::bigint << 32) | objid::bigintという式で再構成することができます。 整数値キーでは、最初のキーがclassid列に、2番目のキーがobjid列に表示され、objsubidは2です。 キーの実際の意味はユーザに任されています。 勧告的ロックはデータベースに対して局所的ですので、勧告的ロックではdatabase列が意味を持ちます。

pg_locksは現行のデータベースに関連するロックのみならず、データベースクラスタ内のすべてのロックに関する全体的なビューを提供します。 relation列はロックされたリレーションを識別するためにpg_class.oidと結合することができますが、これは現行のデータベース内のリレーション(database列が現行のデータベースのOIDまたはゼロとなっているもの)に対してのみ正常に動作します。

それぞれのロックを保持もしくは待機しているセッションのさらなる情報を入手するためpg_stat_activityビューのpid列とpid列を結合することができます。 例えば、このような感じです。

SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa
    ON pl.pid = psa.pid;

また、プリペアードトランザクションを使用している場合には、ロックを保持しているプリペアードトランザクションに関してより多くの情報を得るため、virtualtransaction列は、pg_prepared_xactsビューのtransaction列と結合することができます。 (プリペアードトランザクションはロックを待つことはありませんが、実行時に獲得したロックを保持し続けます。) 例えば、このような感じです。

SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
    ON pl.virtualtransaction = '-1/' || ppx.transaction;

pg_locksビューとそれ自身の結合によって、どのプロセスが他のどのプロセスをブロックしているかの情報を入手することが可能ですが、同時に詳細な正しい情報を得ることは非常に困難です。 このようなクエリはどのロックモードが他のものと衝突しているかについての知見を書き出すべきです。 さらに悪いことに、pg_locksビューは、ロック待ちキューにてどのプロセスが他のどのプロセスに先行しているかの情報を提供しない、またはどのプロセスが他のクライアントセッションのために動作している並列ワーカプロセスかの情報を提供しません。 待機しているプロセスが、どのプロセスにブロックされているかを識別するためにより良い方法は、pg_blocking_pids()関数(表 9.60を参照してください)を使用することです。

pg_locksビューは、異なるシステムにおける、通常のロックマネージャと述部ロックマネージャの両方からのデータを表示します。 さらに通常のロックマネージャではロックを通常ロックと近道ロックに細分化します。 このデータが完全に一貫性があることは保証されません。 ビューが問い合わせられると、近道ロック(fastpath = trueが真)は、ロックマネージャ全体の状態を凍結することなく、各バックエンドからひとつひとつ収集されます。 このため情報収集期間中にロックが獲得されたり解放されたりされる可能性があります。 しかし、これらのロックはその時点で存在する他のロックと競合することがないことが分かっていることに注意してください。 近道ロックについてすべてのバックエンドを問い合わせた後、通常のロックマネージャの残りは1つの単位としてロックされ、残りすべてのロックの一貫性があるスナップショットを原子的な処理で収集します。 ロックマネージャのロックを解除した後、述部ロックマネージャは同様にロックされ、すべての述部ロックを原子的な処理で収集します。 このように、近道ロックという例外がありますが、各ロックマネージャは一貫性をもった結果セットを生成します。 しかし、両方のロックマネージャを同時にロックしませんので、通常のロックマネージャを問い合わせた後と述部ロックマネージャを問い合わせる前の間にロックが獲得されたり解放されたりされる可能性があります。

このビューが頻繁にアクセスされている場合は、通常もしくは述部ロックマネージャをロックするとデータベースのパフォーマンスに影響があります。 ロックマネージャからデータを取得するために、ロックは必要最低限の時間だけ保持されますが、パフォーマンスに影響がある可能性が全くないわけではありません。