PostgreSQLスキルアップノート(自己啓発のための個人サイト)

テーブルレベルロック・検証編


【一覧に戻る】


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■■■■ PostgreSQL スキルアップノート
■■■■
■◆■■ テーブルレベルロック・検証編
■■■■
■■■■
■■■■ 2013/03/03
■■■■ 使用環境:PostgreSQL9.1.7 (CentOS6.2) 
                                                                   (C) 2013 ohdb
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

テーブルレベルのロックと影響を実際に確認する。


【マニュアル】

第 13章同時実行制御・明示的ロック→●[マニュアル]

LOCK文→●[マニュアル]

SELECT文(FOR UPDATE/FOR SHARE句)→●[マニュアル]

第45章システムカタログ・pg_locks→●[マニュアル]


【その他】
 −



■1■ 復習
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                         
                                                              現在のロックモード 
                                                              | | | | | | | | |
   要求ロックモード        LOCK文以外の代表例                 |1|2|3|4|5|6|7|8|
                                                              | | | | | | | | |
--------------------------------------------------------------+-+-+-+-+-+-+-+-+
1  ACCESS SHARE            SELECT                             | | | | | | | |X|
2  ROW SHARE               SELECT FOR UPDATEおよびSHARE       | | | | | | |X|X|
3  ROW EXCLUSIVE           UPDATE,DELETE,INSERT               | | | | |X|X|X|X|
4  SHARE UPDATE EXCLUSIVE  VACUUM等                           | | | |X|X|X|X|X|
5  SHARE                   CREATE INDEX                       | | |X|X| |X|X|X|
6  SHARE ROW EXCLUSIVE     -                                  | | |X|X|X|X|X|X|
7  EXCLUSIVE               -                                  | |X|X|X|X|X|X|X|
8  ACCESS EXCLUSIVE        VACUUM FULL等                      |X|X|X|X|X|X|X|X|
--------------------------------------------------------------+-+-+-+-+-+-+-+-+



■2■ 準備・実験用テーブル作成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

【□】 実験用テーブル作成

drop table t1;
create table t1 (c1 int,c2 text);
insert into t1 values(1,'aa'),(2,'bb'),(3,'cc');

select * from t1;

 c1 | c2
----+----
  1 | aa
  2 | bb
  3 | cc



■3■ 準備・ロック状態確認用スクリプト
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ロック状態はpg_locksを参照して確認を行う。 (SELECT * FROM pg_locks;)
ここでは簡単に呼び出せるようにPREPAREを定義。
なお、PREPAREはそのセッション限り有効なのでそのターミナルを確認専用として切らずに使うこと。


このスクリプトは本章の理解のためにテーブルレベルのロックのみに絞ってあります。
トラブル調査などの実務用途ではありません。


【term-0 □】 確認用SQLを準備

DEALLOCATE show_pglock;
PREPARE show_pglock AS 
    SELECT l.pid,l.granted,d.datname,l.locktype,relation,relation::regclass,l.mode
    FROM pg_locks l  LEFT JOIN pg_database d ON l.database = d.oid
    WHERE  l.pid != pg_backend_pid()
    AND l.locktype = 'relation'
 ORDER BY l.pid;

   
  ---------------------------------------------------------------------
  l.pid                バックエンドプロセスのpid
  l.granted            ロックが待たされている場合 f
  d.datname            DB名
  l.locktype           ロック対象。今回はテーブルレベル'relation'のみ抽出
  relation             テーブル等oid
  relation::regclass   テーブル等名称
                      (pg_classへ結合の代わりにregclassキャストで名前を取得)
  l.mode               ロックモード
  l.pid != pg_backend_pid()  このSQL自身のロックは結果から除外
  ---------------------------------------------------------------------



(参考)locktype ロック対象オブジェクト

     詳細はマニュアルからは確認できなかったため以下より確認
     Let's Postgres→●[記事]

     locktypeの主なもの
       ・relation                    テーブルレベルのロック
       ・transactionid や tuple      行レベルのロック
       ・extend                      INSERTなどによる特定テーブル拡張で競合


(参考)PREPARE(プリペアド文)

    PREPAREは文解析の負荷軽減が目的の機能であるが一時的な関数用途にも使える。
    「SQL関数」とは異なりセッション内限り有効。
    PREPAREで定義し、EXECUTE name;で実行する。




■4■ 単純にSELECTした場合のロック状態
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

小さなテーブルではすぐにselectが終わりロックが解放されてしまうため、トランザク
ション内でSELECTすることにより確認を行う。
COMMIT/ROLLBACKしない限りSELECT時のロックがそのまま保持される。


【term-1 □】 BEGIN;SELECT * FROM t1;

【term-0 □】 EXECUTE show_pglock;

  pid  | granted |  datname  | locktype | relation | relation |      mode
-------+---------+-----------+----------+----------+----------+-----------------
 16350 | t       | database1 | relation |    19613 | t1       | AccessShareLock


以上より

・t1に対してテーブルロックAccessShareLockが要求された。
・ロックは成功している状態である。(granted列が「t」)




■5■ 単純にUPDATEした場合のロック状態
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

UPDATE文などはpsqlのデフォルトでは自動でコミットがかかってしまうため、確認する
ためには必ずBEGINによりトランザクションの開始を宣言する必要がある。


【term-1 □】 BEGIN; UPDATE t1 set c2='aaaaa' WHERE c1=1;

【term-0 □】 EXECUTE show_pglock;

  pid  | granted |  datname  | locktype | relation | relation |       mode
-------+---------+-----------+----------+----------+----------+------------------
 16350 | t       | database1 | relation |    19613 | t1       | RowExclusiveLock


以上より

・t1に対しテーブルロックてRowExclusiveLockが要求された。
・ロックは成功している状態である。(granted列が「t」)



■6■ 単純にSELECT FOR UPDATEした場合のロック状態
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

【term-1 □】 BEGIN; SELECT * FROM t1 WHERE c1=1 FOR UPDATE;

【term-0 □】 EXECUTE show_pglock;


  pid  | granted |  datname  | locktype | relation | relation |     mode
-------+---------+-----------+----------+----------+----------+--------------
 16350 | t       | database1 | relation |    19613 | t1       | RowShareLock


以上より

・t1に対してテーブルロックRowShareLockが要求された。
・ロックは成功している状態である。(granted列が「t」)




■7■ SELECT(ACCESS SHAREロック)中はACCESS EXCLUSIVEロックが阻まれる確認
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

冒頭のマトリクスで、現在のロックモード「1」に対して要求ロックモード「8」の確認。
ACCESS EXCLUSIVEモードが実運用で使われることは滅多にないが、SELECTがテーブルレベル
ロックを使って他の処理を阻害する動きを確認。

それぞれ別のターミナルから実行して確認する。


 ACCESSSHAREロック

【term-1 □】 BEGIN; SELECT * FROM t1;


 ACCESS EXCLUSIVEロック

【term-2 □】 BEGIN; LOCK t1 IN ACCESS EXCLUSIVE MODE;      ・・待ちが発生



 確認

【term-0 □】 EXECUTE show_pglock;

  pid  | granted |  datname  | locktype | relation | relation |        mode
-------+---------+-----------+----------+----------+----------+---------------------
 16643 | t       | database1 | relation |    19613 | t1       | AccessShareLock
 16655 | f ★待ち| database1 | relation |    19613 | t1       | AccessExclusiveLock


以上より
・t1に対してテーブルロックAccessShareLockが要求された。
・t1に対してテーブルロックAccessExclusiveLockが要求された。
・AccessExclusiveLockは認められず待ちになっている状態である。granted=f



 
■8■ 同じテーブルに双方がUPDATE(ROW EXCLUSIVEロックどうし) 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

互いに同じテーブルをUPDATEしても阻まれることはない。
冒頭のマトリクスで現在のロックモード「3」対要求ロックモード「3」の箇所を参照。
ただし、同じ行を更新した場合には、テーブルレベルのロックではなく行ロックが原因で
阻まれることになる。


1.別の行へ更新した場合
──────────────────────────────

【term-1 □】 BEGIN; UPDATE t1 set c2='aaaaa' WHERE c1=1;

【term-2 □】 BEGIN; UPDATE t1 set c2='bbbbb' WHERE c1=2;

【term-0 □】 EXECUTE show_pglock;

  pid  | granted |  datname  | locktype | relation | relation |       mode
-------+---------+-----------+----------+----------+----------+------------------
 16643 | t       | database1 | relation |    19613 | t1       | RowExclusiveLock
 16655 | t       | database1 | relation |    19613 | t1       | RowExclusiveLock

以上よりどちらのRowExclusiveLockロックも成功している。



2.同一行へ更新した場合
──────────────────────────────

【term-1 □】 BEGIN; UPDATE t1 set c2='aaaaa' WHERE c1=1;

【term-2 □】 BEGIN; UPDATE t1 set c2='aaaaa' WHERE c1=1;     ・・待ちが発生
              
【term-0 □】 EXECUTE show_pglock;

  pid  | granted |  datname  | locktype | relation | relation |       mode
-------+---------+-----------+----------+----------+----------+------------------
 16643 | t       | database1 | relation |    19613 | t1       | RowExclusiveLock
 16655 | t       | database1 | relation |    19613 | t1       | RowExclusiveLock


「term-2」は終了しない状態になっているにも関わらず、両方とも「granted=t」となっている。
これはテーブルロック自体は成功していることを示している。

待ちの原因はもちろん行レベルロックである。

ここではlocktypeがrelationのものだけに絞ってあり、「granted=f」は見えないが、絞らなけ
れば「granted=f」のものが現れてくる。

今回はテーブルレベルロックの確認と、マトリクスの理解が目的のため、ここでは触れず、行レ
ベルロックを含めた確認は章をあらためて行うこととする。


                                                                                                            
以上 
inserted by FC2 system