pg_locks
pg_locks
ビューはデータベースサーバ内でアクティブなプロセスによって保持されたロックに関する情報へのアクセスを提供します。
ロックに関するより詳細な説明は第13章を参照してください。
pg_locks
にはロック対象となる進行中のオブジェクト、要求されたロックモード、および関連するプロセス毎に1つの行を持ちます。
ですから、もし複数のプロセスが同じロック対象オブジェクトに対してロックを保持していたりロックを待機している場合には、同じロック対象オブジェクトが何度も出現することがあります。
しかし現在ロックされていないオブジェクトはまったく現れません。
ロック対象オブジェクトには異なる型がいくつか存在します。
リレーション全体(例:テーブル)、リレーションの個別のページ、リレーションの個別のタプル、トランザクションID(仮想と永続の両方のID)、一般的なデータベースオブジェクト(これはpg_description
やpg_depend
と同様にクラスOIDとオブジェクトOIDで識別されます)。
さらに、リレーションを拡張する権利は、別のロック対象オブジェクトとして表現されます。
また「勧告的」ロックはユーザ定義の意味を持つ複数から形成されるかもしれません。
表52.74 pg_locks
の列
名前 | 型 | 参照先 | 説明 |
---|---|---|---|
locktype | text |
ロック対象オブジェクトの種類。
relation 、
extend 、
page 、
tuple 、
transactionid 、
virtualxid 、
object 、
userlock 、
advisory
| |
database | oid |
| ロック対象が存在しているデータベースのOID。対象が共有オブジェクトの場合はゼロ。対象がトランザクションIDである場合はNULL。 |
relation | oid |
| ロックの対象となるリレーションのOID。対象がリレーションではない場合かリレーションの一部である場合はNULL。 |
page | integer | ロックの対象となるリレーション内のページ番号。対象がタプルもしくはリレーションページではない場合はNULL。 | |
tuple | smallint | ページ内のロックの対象となっているタプル番号。対象がタプルではない場合はNULL。 | |
virtualxid | text | ロックの対象となるトランザクションの仮想ID。対象が仮想トランザクションIDではない場合はNULL。 | |
transactionid | xid | ロックの対象となるトランザクションのID。対象がトランザクションIDではない場合はNULL。 | |
classid | oid |
| ロックの対象を含むシステムカタログのOID。対象が一般的なデータベースオブジェクトではない場合はNULL。 |
objid | oid | any OID column | システムカタログ内のロックの対象のOID。 対象が一般的なデータベースオブジェクトでない場合はNULL。 |
objsubid | smallint |
ロック対象の列番号(classid とobjid はテーブル自身を参照します)、その他の一般的なデータベースオブジェクトではゼロ、一般的ではないデータベースオブジェクトではNULLです。
| |
virtualtransaction | text | ロックを保持、もしくは待っている仮想トランザクションID。 | |
pid | integer | ロックを保持、もしくは待っているサーバプロセスのプロセスID。 ただしプリペアードトランザクションによりロックが保持されている場合はNULL。 | |
mode | text | このプロセスで保持または要求するロックモードの名称。 (13.3.1 and 13.2.3参照) | |
granted | boolean | ロックが保持されている場合は真、ロックが待ち状態の場合は偽 | |
fastpath | boolean | ファストパス経由でロックが獲得されている場合は真、メインロックテーブル経由で獲得されている場合は偽。 |
指定されたプロセスにより保持されているロックを表す行内では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つの単位としてロックされ、残りすべてのロックの一貫性があるスナップショットを原子的な処理で収集します。
ロックマネージャのロックを解除した後、述部ロックマネージャは同様にロックされ、すべての述部ロックを原子的な処理で収集します。
このように、近道ロックという例外がありますが、各ロックマネージャは一貫性をもった結果セットを生成します。
しかし、両方のロックマネージャを同時にロックしませんので、通常のロックマネージャを問い合わせた後と述部ロックマネージャを問い合わせる前の間にロックが獲得されたり解放されたりされる可能性があります。
このビューが頻繁にアクセスされている場合は、通常もしくは述部ロックマネージャをロックするとデータベースのパフォーマンスに影響があります。 ロックマネージャからデータを取得するために、ロックは必要最低限の時間だけ保持されますが、パフォーマンスに影響がある可能性が全くないわけではありません。