LoginSignup
2
3

More than 5 years have passed since last update.

PostgreSQLで行ロックの状態を確認する

Last updated at Posted at 2017-11-27

pg_locks ではよくわからない

PostgreSQLのロックの確認手段としては pg_locks テーブルが存在するが、このテーブルには「テーブルロック」と「未獲得の行ロック」しか含まれていない。

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

未獲得状態の行ロックについても、 pg_locks では mode カラムで RowShareLock といったざっくりとした分類しか表示されず、「FOR UPDATE」「FOR NO KEY UPDATE」「FOR SHARE」「FOR KEY SHARE」のいずれの状態でロックを取得しようとしているのかがわからない。

pgrowlocks を使う

Tatsuo Ishii さんが pgrowlocks というモジュールを提供されているようなので、こちらを使ってみると良い感じ。便利。

CREATE EXTENSION pgrowlocks;

で現在のデータベースに対して pgrowlocks 拡張を追加したら、あとはこんな感じで使える。

dbname=# SELECT * FROM pgrowlocks('tablename');

 locked_row | locker | multi |   xids   |     modes      | pids  
------------+--------+-------+----------+----------------+-------
 (91,14)    | 107127 | f     | {107127} | {"For Update"} | {190}
(1 row)

具体的なレコードについては locked_row の値と該当テーブルが隠し持つシステム列 ctid カラムの一致を確認すれば良いです。したがって以下のようにコマンドを打てばOK。

SELECT * FROM tablename AS t, pgrowlocks('tablename') AS p WHERE p.locked_row = t.ctid;

各カラムの意味についてはドキュメントを参照。

よく見たらドキュメントに書かれている結果出力例が実際の出力結果と違う……。ドキュメントでは
lock_type カラムにロックモード情報が含まれるように書いているが、上記の通り modes カラムで返ってくる(PostgreSQL 9.3あたりのLockモード追加されたことにあわせて仕様変わったのにドキュメント更新が漏れているだけだと思う)。

補足

  • pgrowlocks で取得されるのは獲得済みの行ロックのみのようなので、獲得待ち状態の行ロックについては pg_locks で確認する。
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3