バージョンごとのドキュメント一覧

13.3. 明示的ロック #

<title>Explicit Locking</title>

<productname>PostgreSQL</productname> provides various lock modes to control concurrent access to data in tables. These modes can be used for application-controlled locking in situations where <acronym>MVCC</acronym> does not give the desired behavior. Also, most <productname>PostgreSQL</productname> commands automatically acquire locks of appropriate modes to ensure that referenced tables are not dropped or modified in incompatible ways while the command executes. (For example, <command>TRUNCATE</command> cannot safely be executed concurrently with other operations on the same table, so it obtains an <literal>ACCESS EXCLUSIVE</literal> lock on the table to enforce that.) PostgreSQLは、テーブル内のデータに対する同時アクセスを制御するために様々な種類のロックモードを備えています。 これらのモードは、MVCCでは必要な動作を得られない場合、アプリケーション制御のロックに使用できます。 また、ほとんどのPostgreSQLコマンドでは、参照されるテーブルがそのコマンドの実行中に別の方法で削除もしくは変更されていないことを確実にするために、適切なモードのロックを自動的に獲得します。 (例えば、TRUNCATEコマンドは、同じテーブルに対する他の操作と同時に安全に実行することはできないので、それを確実に実行するため、そのテーブルのACCESS EXCLUSIVEロックを獲得します。)

To examine a list of the currently outstanding locks in a database server, use the <link linkend="view-pg-locks"><structname>pg_locks</structname></link> system view. For more information on monitoring the status of the lock manager subsystem, refer to <xref linkend="monitoring"/>. 現在のデータベースサーバに残っているロックの一覧を確認するには、pg_locksシステムビューを使用してください。 ロック管理サブシステムの状況監視についての詳細は第28章を参照してください。

13.3.1. テーブルレベルロック #

<title>Table-Level Locks</title>

The list below shows the available lock modes and the contexts in which they are used automatically by <productname>PostgreSQL</productname>. You can also acquire any of these locks explicitly with the command <xref linkend="sql-lock"/>. Remember that all of these lock modes are table-level locks, even if the name contains the word <quote>row</quote>; the names of the lock modes are historical. To some extent the names reflect the typical usage of each lock mode &mdash; but the semantics are all the same. The only real difference between one lock mode and another is the set of lock modes with which each conflicts (see <xref linkend="table-lock-compatibility"/>). Two transactions cannot hold locks of conflicting modes on the same table at the same time. (However, a transaction never conflicts with itself. For example, it might acquire <literal>ACCESS EXCLUSIVE</literal> lock and later acquire <literal>ACCESS SHARE</literal> lock on the same table.) Non-conflicting lock modes can be held concurrently by many transactions. Notice in particular that some lock modes are self-conflicting (for example, an <literal>ACCESS EXCLUSIVE</literal> lock cannot be held by more than one transaction at a time) while others are not self-conflicting (for example, an <literal>ACCESS SHARE</literal> lock can be held by multiple transactions). 以下のリストに、使用可能なロックモードとそれらがPostgreSQLで自動的に使用される文脈を示します。 また、LOCKコマンドを使用して、こうしたロックを明示的に獲得することもできます。 これらのロックモードは、たとえその名前にrow(行)という言葉が付いていても、全てテーブルレベルのロックであることに注意してください。 ロックモードの名前は歴史的なものです。 これらの名前は、各ロックモードの代表的な使用方法をある程度表しています。 しかし、意味的には全て同じです。 ロックモード間における唯一の実質的な差異は、どのモードがどのモードと競合するかというロックモードの組み合わせです(表 13.2を参照してください)。 2つのトランザクションで、競合するモードのロックを同時に同一テーブル上に保持することはできません (しかし、トランザクションは自分自身とは決して競合しません。 例えば、ACCESS EXCLUSIVEロックを獲得し、その後同じテーブルにACCESS SHAREロックを獲得できる可能性があります)。 競合しないロックモードは、多くのトランザクションで同時に保持できます。 特に、ロックモードには、自己競合するもの(例えば、ACCESS EXCLUSIVEは同時に複数のトランザクションで保持することは不可能)と、自己競合しないもの(例えば、ACCESS SHAREは複数のトランザクションで保持可能)があることに注意してください。

テーブルレベルロックモード

<title>Table-Level Lock Modes</title>
ACCESS SHARE (AccessShareLock)

Conflicts with the <literal>ACCESS EXCLUSIVE</literal> lock mode only. ACCESS EXCLUSIVEロックモードとのみ競合します。

The <command>SELECT</command> command acquires a lock of this mode on referenced tables. In general, any query that only <emphasis>reads</emphasis> a table and does not modify it will acquire this lock mode. SELECTコマンドにより、参照されるテーブルに対してこのモードのロックが獲得されます。 通常、テーブルの読み取りのみで変更を行わない問い合わせであれば全て、このロックモードを獲得します。

ROW SHARE (RowShareLock)

Conflicts with the <literal>EXCLUSIVE</literal> and <literal>ACCESS EXCLUSIVE</literal> lock modes. EXCLUSIVEおよびACCESS EXCLUSIVEロックモードと競合します。

The <command>SELECT</command> command acquires a lock of this mode on all tables on which one of the <option>FOR UPDATE</option>, <option>FOR NO KEY UPDATE</option>, <option>FOR SHARE</option>, or <option>FOR KEY SHARE</option> options is specified (in addition to <literal>ACCESS SHARE</literal> locks on any other tables that are referenced without any explicit <option>FOR ...</option> locking option). (明示的なFOR ...ロックオプションなしで参照される他のすべてのテーブルで取得されるACCESS SHAREロックに加え)SELECTコマンドは、FOR UPDATEFOR NO KEY UPDATEFOR SHARE、またはFOR KEY SHAREオプションのいずれかが指定されているすべてのテーブルでこのモードのロックを取得します。

ROW EXCLUSIVE (RowExclusiveLock)

Conflicts with the <literal>SHARE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal> lock modes. SHARESHARE ROW EXCLUSIVEEXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。

The commands <command>UPDATE</command>, <command>DELETE</command>, <command>INSERT</command>, and <command>MERGE</command> acquire this lock mode on the target table (in addition to <literal>ACCESS SHARE</literal> locks on any other referenced tables). In general, this lock mode will be acquired by any command that <emphasis>modifies data</emphasis> in a table. UPDATEDELETEINSERTおよびMERGEコマンドは、(参照される他の全てのテーブルに対するACCESS SHAREロックに加えて)対象となるテーブル上にこのモードのロックを獲得します。 通常、このロックモードは、テーブルのデータを変更する問い合わせにより獲得されます。

SHARE UPDATE EXCLUSIVE (ShareUpdateExclusiveLock)

Conflicts with the <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal> lock modes. This mode protects a table against concurrent schema changes and <command>VACUUM</command> runs. SHARE UPDATE EXCLUSIVESHARESHARE ROW EXCLUSIVEEXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。 このモードにより、同時実行されるスキーマの変更およびVACUUMコマンドの実行から、テーブルを保護します。

Acquired by <command>VACUUM</command> (without <option>FULL</option>), <command>ANALYZE</command>, <command>CREATE INDEX CONCURRENTLY</command>, <command>CREATE STATISTICS</command>, <command>COMMENT ON</command>, <command>REINDEX CONCURRENTLY</command>, and certain <link linkend="sql-alterindex"><command>ALTER INDEX</command></link> and <link linkend="sql-altertable"><command>ALTER TABLE</command></link> variants (for full details see the documentation of these commands). FULLなしの)VACUUMANALYZECREATE INDEX CONCURRENTLYCREATE STATISTICSCOMMENT ONREINDEX CONCURRENTLY、ある種のALTER INDEXALTER TABLEの変種で取得されます(完全な詳細はこれらのコマンドの文書を見てください)。

SHARE (ShareLock)

Conflicts with the <literal>ROW EXCLUSIVE</literal>, <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal> lock modes. This mode protects a table against concurrent data changes. ROW EXCLUSIVESHARE UPDATE EXCLUSIVESHARE ROW EXCLUSIVEEXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。 このモードは、同時実行されるデータ変更からテーブルを保護します。

Acquired by <command>CREATE INDEX</command> (without <option>CONCURRENTLY</option>). CONCURRENTLYなしの)CREATE INDEXによって獲得されます。

SHARE ROW EXCLUSIVE (ShareRowExclusiveLock)

Conflicts with the <literal>ROW EXCLUSIVE</literal>, <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal> lock modes. This mode protects a table against concurrent data changes, and is self-exclusive so that only one session can hold it at a time. ROW EXCLUSIVESHARE UPDATE EXCLUSIVESHARESHARE ROW EXCLUSIVEEXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。 このモードは、1つのセッションだけが一度にそれを保持できるよう、自己排他的に同時のデータ変更からテーブルを保護します。

Acquired by <command>CREATE TRIGGER</command> and some forms of <link linkend="sql-altertable"><command>ALTER TABLE</command></link>. CREATE TRIGGER、および、ALTER TABLEのいくつかの形式により獲得されます。

EXCLUSIVE (ExclusiveLock)

Conflicts with the <literal>ROW SHARE</literal>, <literal>ROW EXCLUSIVE</literal>, <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal> lock modes. This mode allows only concurrent <literal>ACCESS SHARE</literal> locks, i.e., only reads from the table can proceed in parallel with a transaction holding this lock mode. ROW SHAREROW EXCLUSIVESHARE UPDATE EXCLUSIVESHARESHARE ROW EXCLUSIVEEXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。 このモードは、同時実行されるACCESS SHAREのみを許可します。 つまり、このロックモードを保持するトランザクションと並行して実行できる処理は、テーブルの読み取りだけです。

Acquired by <command>REFRESH MATERIALIZED VIEW CONCURRENTLY</command>. REFRESH MATERIALIZED VIEW CONCURRENTLYにより獲得されます。

ACCESS EXCLUSIVE (AccessExclusiveLock)

Conflicts with locks of all modes (<literal>ACCESS SHARE</literal>, <literal>ROW SHARE</literal>, <literal>ROW EXCLUSIVE</literal>, <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and <literal>ACCESS EXCLUSIVE</literal>). This mode guarantees that the holder is the only transaction accessing the table in any way. 全てのモードのロック(ACCESS SHAREROW SHAREROW EXCLUSIVESHARE UPDATE EXCLUSIVESHARESHARE ROW EXCLUSIVEEXCLUSIVE、および ACCESS EXCLUSIVE)と競合します。 このモードにより、その保持者以外にテーブルにアクセスするトランザクションがないことを保証されます。

Acquired by the <command>DROP TABLE</command>, <command>TRUNCATE</command>, <command>REINDEX</command>, <command>CLUSTER</command>, <command>VACUUM FULL</command>, and <command>REFRESH MATERIALIZED VIEW</command> (without <option>CONCURRENTLY</option>) commands. Many forms of <command>ALTER INDEX</command> and <command>ALTER TABLE</command> also acquire a lock at this level. This is also the default lock mode for <command>LOCK TABLE</command> statements that do not specify a mode explicitly. DROP TABLETRUNCATEREINDEXCLUSTERVACUUM FULL、(CONCURRENTLYなしの)REFRESH MATERIALIZED VIEWコマンドによって獲得されます。 ALTER INDEXALTER TABLEの多くの形式もこのレベルでロックを獲得します。 これはまた、明示的にモードを指定しないLOCK TABLE文のデフォルトのロックモードです。

ヒント

Only an <literal>ACCESS EXCLUSIVE</literal> lock blocks a <command>SELECT</command> (without <option>FOR UPDATE/SHARE</option>) statement. ACCESS EXCLUSIVEロックのみが、SELECTFOR UPDATE/SHAREなし)文をブロックします。

Once acquired, a lock is normally held until the end of the transaction. But if a lock is acquired after establishing a savepoint, the lock is released immediately if the savepoint is rolled back to. This is consistent with the principle that <command>ROLLBACK</command> cancels all effects of the commands since the savepoint. The same holds for locks acquired within a <application>PL/pgSQL</application> exception block: an error escape from the block releases locks acquired within it. 通常ロックは獲得した後、トランザクションの終わりまで保持されます。 しかし、ロックがセーブポイントの確立後に獲得された場合、セーブポイントがロールバックされると、ロックは即座に解放されます。 これは、ROLLBACKがセーブポイント以降に行われたすべてのコマンドの効果を取り消すという原則と整合性が取れています。 PL/pgSQL例外ブロック内で獲得されたロックに対しても同様です。 そのブロックからエラーで抜けた後、獲得されたロックは解放されます。

表13.2 ロックモードの競合

<title>Conflicting Lock Modes</title>
要求するロックモード既存のロックモード
ACCESS SHAREROW SHAREROW EXCL.SHARE UPDATE EXCL.SHARESHARE ROW EXCL.EXCL.ACCESS EXCL.
ACCESS SHARE       X
ROW SHARE      XX
ROW EXCL.    XXXX
SHARE UPDATE EXCL.   XXXXX
SHARE  XX XXX
SHARE ROW EXCL.  XXXXXX
EXCL. XXXXXXX
ACCESS EXCL.XXXXXXXX

13.3.2. 行レベルロック #

<title>Row-Level Locks</title>

In addition to table-level locks, there are row-level locks, which are listed as below with the contexts in which they are used automatically by <productname>PostgreSQL</productname>. See <xref linkend="row-lock-compatibility"/> for a complete table of row-level lock conflicts. Note that a transaction can hold conflicting locks on the same row, even in different subtransactions; but other than that, two transactions can never hold conflicting locks on the same row. Row-level locks do not affect data querying; they block only <emphasis>writers and lockers</emphasis> to the same row. Row-level locks are released at transaction end or during savepoint rollback, just like table-level locks. テーブルレベルロックに加えて、行レベルロックがあります。PostgreSQLが自動的に使う文脈付きで以下に行レベルロックの一覧があります。 行レベルロックの競合の完全な表については表 13.3を参照してください。 トランザクションは異なる副トランザクション内であっても、同じ行に対して競合するロックを保持できることに注意してください。 しかし、それ以外では、二つのトランザクションは同じ行に対して競合するロックを決して保持できません。 行レベルロックは、データの問い合わせには影響を与えません。 行レベルロックは、同じ行に対する書き込みとロックだけをブロックします。 テーブルレベルロックと同じように、行レベルロックはトランザクションの終わり、または、セーブポイントへのロールバックで解放されます。

行レベルロックモード

<title>Row-Level Lock Modes</title>
FOR UPDATE

<literal>FOR UPDATE</literal> causes the rows retrieved by the <command>SELECT</command> statement to be locked as though for update. This prevents them from being locked, modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt <command>UPDATE</command>, <command>DELETE</command>, <command>SELECT FOR UPDATE</command>, <command>SELECT FOR NO KEY UPDATE</command>, <command>SELECT FOR SHARE</command> or <command>SELECT FOR KEY SHARE</command> of these rows will be blocked until the current transaction ends; conversely, <command>SELECT FOR UPDATE</command> will wait for a concurrent transaction that has run any of those commands on the same row, and will then lock and return the updated row (or no row, if the row was deleted). Within a <literal>REPEATABLE READ</literal> or <literal>SERIALIZABLE</literal> transaction, however, an error will be thrown if a row to be locked has changed since the transaction started. For further discussion see <xref linkend="applevel-consistency"/>. FOR UPDATEによりSELECT文により取り出された行が更新用であるかのようにロックされます。 これにより、それらは現在のトランザクションが終わるまで、他のトランザクションがロック、変更、削除できなくなります。 すなわち、これらの行に対してUPDATEDELETESELECT FOR UPDATESELECT FOR NO KEY UPDATESELECT FOR SHARESELECT FOR KEY SHAREをしようとする他のトランザクションは現在のトランザクションが終わるまでブロックされます。逆に言えば、SELECT FOR UPDATEは同じ行に対して上記のコマンドを実行している同時実行トランザクションを待ち、それから更新された行をロックして返します(行が削除されていれば、行は返しません)。 しかし、REPEATABLE READもしくはSERIALIZABLEトランザクション内では、ロックする行がトランザクションの開始した後に変更された場合にはエラーが返ります。 これ以上の議論は13.4を参照してください。

The <literal>FOR UPDATE</literal> lock mode is also acquired by any <command>DELETE</command> on a row, and also by an <command>UPDATE</command> that modifies the values of certain columns. Currently, the set of columns considered for the <command>UPDATE</command> case are those that have a unique index on them that can be used in a foreign key (so partial indexes and expressional indexes are not considered), but this may change in the future. FOR UPDATEロックモードは行に対するDELETEでも、ある列の値を変更するUPDATEでも獲得されます。 現時点では、UPDATEの場合に考慮される列の集合は、外部キーとして使うことのできる一意のインデックス(つまり部分インデックスや式インデックスは考慮されません)があるものですが、これは将来変わるかもしれません。

FOR NO KEY UPDATE

Behaves similarly to <literal>FOR UPDATE</literal>, except that the lock acquired is weaker: this lock will not block <literal>SELECT FOR KEY SHARE</literal> commands that attempt to acquire a lock on the same rows. This lock mode is also acquired by any <command>UPDATE</command> that does not acquire a <literal>FOR UPDATE</literal> lock. 獲得するロックが弱い以外はFOR UPDATEと同じように振る舞います。このロックは同じ行のロックを獲得しようとするSELECT FOR KEY SHAREコマンドをブロックしません。 このロックモードはFOR UPDATEロックを獲得しないUPDATEによっても獲得されます。

FOR SHARE

Behaves similarly to <literal>FOR NO KEY UPDATE</literal>, except that it acquires a shared lock rather than exclusive lock on each retrieved row. A shared lock blocks other transactions from performing <command>UPDATE</command>, <command>DELETE</command>, <command>SELECT FOR UPDATE</command> or <command>SELECT FOR NO KEY UPDATE</command> on these rows, but it does not prevent them from performing <command>SELECT FOR SHARE</command> or <command>SELECT FOR KEY SHARE</command>. 取り出された各行に対して排他ロックではなく共有ロックを獲得する以外は、FOR NO KEY UPDATEと同じように振る舞います。 共有ロックは、他のトランザクションがこれらの行に対してUPDATEDELETESELECT FOR UPDATESELECT FOR NO KEY UPDATEを実行するのをブロックしますが、SELECT FOR SHARESELECT FOR KEY SHAREを実行するのを阻害しません。

FOR KEY SHARE

Behaves similarly to <literal>FOR SHARE</literal>, except that the lock is weaker: <literal>SELECT FOR UPDATE</literal> is blocked, but not <literal>SELECT FOR NO KEY UPDATE</literal>. A key-shared lock blocks other transactions from performing <command>DELETE</command> or any <command>UPDATE</command> that changes the key values, but not other <command>UPDATE</command>, and neither does it prevent <command>SELECT FOR NO KEY UPDATE</command>, <command>SELECT FOR SHARE</command>, or <command>SELECT FOR KEY SHARE</command>. 獲得するロックが弱い以外はFOR SHAREと同じように振る舞います。SELECT FOR UPDATEはブロックされますが、SELECT FOR NO KEY UPDATEはブロックされません。 キー共有ロックは、他のトランザクションがDELETEやキー値を変更するUPDATEを実行するのをブロックしますが、それ以外のUPDATEや、SELECT FOR NO KEY UPDATESELECT FOR SHARESELECT FOR KEY SHAREを阻害しません。

<productname>PostgreSQL</productname> doesn't remember any information about modified rows in memory, so there is no limit on the number of rows locked at one time. However, locking a row might cause a disk write, e.g., <command>SELECT FOR UPDATE</command> modifies selected rows to mark them locked, and so will result in disk writes. PostgreSQLでは、メモリ上に変更された行の情報を記憶しないため、同時にロックできる行数の上限はありません。 しかし、行をロックする際に、ディスクに書き込む作業が発生するかもしれません。 例えばSELECT FOR UPDATEは、選択された行をロックしたものと印を付けるために変更を行いますので、ディスクにその結果を書き込むことになります。

表13.3 行レベルロックの競合

<title>Conflicting Row-Level Locks</title>
要求するロックモード現在のロックモード
FOR KEY SHAREFOR SHAREFOR NO KEY UPDATEFOR UPDATE
FOR KEY SHARE   X
FOR SHARE  XX
FOR NO KEY UPDATE XXX
FOR UPDATEXXXX

13.3.3. ページレベルロック #

<title>Page-Level Locks</title>

In addition to table and row locks, page-level share/exclusive locks are used to control read/write access to table pages in the shared buffer pool. These locks are released immediately after a row is fetched or updated. Application developers normally need not be concerned with page-level locks, but they are mentioned here for completeness. テーブルと行ロックに加え、ページレベルの共有/排他ロックがあり、これらは共有バッファプールにあるテーブルページへの読み書きのアクセスを管理するために使用されます。 これらのロックは、行が取得された後や更新された後に即座に解除されます。 アプリケーション開発者は通常ページレベルロックを考慮する必要はありませんが、ロックについて全てを説明したかったためここで取り上げました。

13.3.4. デッドロック #

<title>Deadlocks</title>

The use of explicit locking can increase the likelihood of <firstterm>deadlocks</firstterm>, wherein two (or more) transactions each hold locks that the other wants. For example, if transaction 1 acquires an exclusive lock on table A and then tries to acquire an exclusive lock on table B, while transaction 2 has already exclusive-locked table B and now wants an exclusive lock on table A, then neither one can proceed. <productname>PostgreSQL</productname> automatically detects deadlock situations and resolves them by aborting one of the transactions involved, allowing the other(s) to complete. (Exactly which transaction will be aborted is difficult to predict and should not be relied upon.) 明示的なロックの使用は、デッドロックの原因となる可能性があります。 デッドロックとは、2つ(もしくはそれ以上)のトランザクションにおいて、それぞれが、他方のトランザクションが必要とするロックを所持してしまうことです。 例えば、トランザクション1がテーブルAに排他ロックを獲得していて、次にテーブルBに排他ロックを獲得しようとする際に、トランザクション2が既にテーブルBに排他ロックを獲得済みであって、今からテーブルAに排他ロックを獲得しようと試みる場合、どちらのトランザクションも処理を進められません。 PostgreSQLでは、自動的にデッドロック状況を検知し、関係するトランザクションの一方をアボートすることにより、この状況を解決し、もう一方のトランザクションの処理を完了させます (どちらのトランザクションをアボートするかを正確に予期するのは難しく、これに依存すべきではありません)。

Note that deadlocks can also occur as the result of row-level locks (and thus, they can occur even if explicit locking is not used). Consider the case in which two concurrent transactions modify a table. The first transaction executes: デッドロックは行レベルロックの結果として発生する可能性があります (したがって、明示的なロック処理を使用していなくても発生する可能性があります)。 2つの同時実行トランザクションがあるテーブルを変更する状況を考えてみます。 1つ目のトランザクションは以下を実行します。

UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 11111;

This acquires a row-level lock on the row with the specified account number. Then, the second transaction executes: これは、指定した口座番号の行に対し行レベルロックを獲得します。 次に2番目のトランザクションが以下を実行します。

UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 22222;
UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 11111;

The first <command>UPDATE</command> statement successfully acquires a row-level lock on the specified row, so it succeeds in updating that row. However, the second <command>UPDATE</command> statement finds that the row it is attempting to update has already been locked, so it waits for the transaction that acquired the lock to complete. Transaction two is now waiting on transaction one to complete before it continues execution. Now, transaction one executes: 1つ目のUPDATE文は指定された行に対する行レベルロックの獲得に成功し、この行の更新に成功します。 しかし、2つ目のUPDATE文は、更新対象の行がロックされていることを検知し、ロックを獲得したトランザクションが完了するまで待機します。 トランザクション2は、ここで、続きを実行する前にトランザクション1が完了するのを待機しています。 さて、トランザクション1がここで以下を実行します。

UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;

Transaction one attempts to acquire a row-level lock on the specified row, but it cannot: transaction two already holds such a lock. So it waits for transaction two to complete. Thus, transaction one is blocked on transaction two, and transaction two is blocked on transaction one: a deadlock condition. <productname>PostgreSQL</productname> will detect this situation and abort one of the transactions. トランザクション1は指定した行の行レベルロックを獲得しようとしますが、これは不可能です。 トランザクション2がそのロックを既に獲得しているからです。 そのため、トランザクション2が完了するのを待機することになります。 こうして、トランザクション1はトランザクション2でブロックされ、トランザクション2はトランザクション1でブロックされる、つまり、デッドロック状態です。 PostgreSQLはデッドロック状態を検知し、片方のトランザクションを中断させます。

The best defense against deadlocks is generally to avoid them by being certain that all applications using a database acquire locks on multiple objects in a consistent order. In the example above, if both transactions had updated the rows in the same order, no deadlock would have occurred. One should also ensure that the first lock acquired on an object in a transaction is the most restrictive mode that will be needed for that object. If it is not feasible to verify this in advance, then deadlocks can be handled on-the-fly by retrying transactions that abort due to deadlocks. デッドロックを防ぐ最も良い方法は、データベースを使用する全てのアプリケーションが、整合性のある順序で複数のオブジェクトに対するロックを獲得することです。 前に示したデッドロックの例で、もし両方のトランザクションで同じ順序で行を更新していたらデッドロックは起こりません。 また、トランザクション内のオブジェクトに対して獲得した最初のロックが、そのオブジェクトが必要とする最も制限的なモードであることを確実に保証すべきです。 このことが事前に検証できない場合、デッドロックによりアボートするトランザクションを再試行すれば、デッドロックをデータベースを稼働させながらでも処理できます。

So long as no deadlock situation is detected, a transaction seeking either a table-level or row-level lock will wait indefinitely for conflicting locks to be released. This means it is a bad idea for applications to hold transactions open for long periods of time (e.g., while waiting for user input). デッドロック状況が検出されなければ、テーブルレベルロックもしくは行レベルロックを要求するトランザクションは、競合するロックが解放されるまで、無期限に待機します。 したがって、アプリケーションで長時間(例えば、ユーザの入力待ち)トランザクションを開いたまま保持しておくのは、推奨されません。

13.3.5. 勧告的ロック #

<title>Advisory Locks</title>

<productname>PostgreSQL</productname> provides a means for creating locks that have application-defined meanings. These are called <firstterm>advisory locks</firstterm>, because the system does not enforce their use &mdash; it is up to the application to use them correctly. Advisory locks can be useful for locking strategies that are an awkward fit for the MVCC model. For example, a common use of advisory locks is to emulate pessimistic locking strategies typical of so-called <quote>flat file</quote> data management systems. While a flag stored in a table could be used for the same purpose, advisory locks are faster, avoid table bloat, and are automatically cleaned up by the server at the end of the session. PostgreSQLは、アプリケーション独自の意味を持つロックを生成する手法を提供します。 これは、その使用に関してシステムによる制限がないこと、つまり、正しい使用に関してはアプリケーションが責任を持つことから勧告的ロックと呼ばれます。 勧告的ロックは、MVCC方式に合わせづらいロック戦略で有用に使用することができます。 例えば、勧告的ロックのよくある利用として、いわゆるフラットファイルデータ管理システムで典型的な、悲観的なロック戦略を模擬することです。 この用途のためにテーブル内にフラグを格納することもできますが、勧告的ロックの方が高速で、テーブルの膨張を防ぐことができます。 また、セッション終了時にサーバによる自動整理を行うこともできるようになります。

There are two ways to acquire an advisory lock in <productname>PostgreSQL</productname>: at session level or at transaction level. Once acquired at session level, an advisory lock is held until explicitly released or the session ends. Unlike standard lock requests, session-level advisory lock requests do not honor transaction semantics: a lock acquired during a transaction that is later rolled back will still be held following the rollback, and likewise an unlock is effective even if the calling transaction fails later. A lock can be acquired multiple times by its owning process; for each completed lock request there must be a corresponding unlock request before the lock is actually released. Transaction-level lock requests, on the other hand, behave more like regular lock requests: they are automatically released at the end of the transaction, and there is no explicit unlock operation. This behavior is often more convenient than the session-level behavior for short-term usage of an advisory lock. Session-level and transaction-level lock requests for the same advisory lock identifier will block each other in the expected way. If a session already holds a given advisory lock, additional requests by it will always succeed, even if other sessions are awaiting the lock; this statement is true regardless of whether the existing lock hold and new request are at session level or transaction level. PostgreSQLには、セッションレベルとトランザクションレベルという2つの勧告的ロックの獲得方法があります。 セッションレベルで獲得すると、勧告的ロックは明示的に解放されるか、セッションが終了するまで保持されます。 標準のロック要求と異なり、セッションレベル勧告的ロックはトランザクションという意味には従いません。 ロックがトランザクション期間中に獲得され、そのトランザクションを後でロールバックしたとしても、ロールバック後も保持されます。 そして、呼び出し元のトランザクションが後で失敗したとしてもロック解除は有効です。 所有するプロセスの中で、同一のセッションレベルのロックを複数回獲得することもできます。 この場合、個々のロック要求に対して、ロックを実際に解放する前に対応するロック解除要求がなければなりません。 一方トランザクションレベルのロックはより通常のロックに似たように動作します。 それらは、処理の終わりに自動的に解放されますので、明示的なロック解放操作はありません。 短期間の勧告的ロックを利用する場合は、セッションレベルの動作よりもこの動作の方が便利なことが多くあります。 同じ勧告的ロック識別子に対するセッションレベルのロックとトランザクションレベルのロック要求は、想像通り互いをブロックします。 セッションがすでに指定された勧告的ロックを保持している場合、他のセッションがそのロックを待機していたとしても、追加の要求は常に成功します。 これは保持されているロックと新しい要求がセッションレベルかトランザクションレベルかに関わらず、この文は当てはまります。

Like all locks in <productname>PostgreSQL</productname>, a complete list of advisory locks currently held by any session can be found in the <link linkend="view-pg-locks"><structname>pg_locks</structname></link> system view. PostgreSQLにおけるすべてのロックと同様に、現時点ですべてのセッションで保持されている勧告的ロックの全一覧はpg_locksシステムビューにあります。

Both advisory locks and regular locks are stored in a shared memory pool whose size is defined by the configuration variables <xref linkend="guc-max-locks-per-transaction"/> and <xref linkend="guc-max-connections"/>. Care must be taken not to exhaust this memory or the server will be unable to grant any locks at all. This imposes an upper limit on the number of advisory locks grantable by the server, typically in the tens to hundreds of thousands depending on how the server is configured. 勧告的ロックと通常のロックは共有メモリプールに割り当てられ、その容量はmax_locks_per_transactionmax_connections設定変数により決定されます。 このメモリを浪費しないように注意が必要です。 さもないと、サーバはロック獲得をまったく許可することができなくなります。 これは、サーバで許可できる勧告的ロック数に上限があることを意味します。 サーバの設定によりますが、通常、1万から10万程度になります。

In certain cases using advisory locking methods, especially in queries involving explicit ordering and <literal>LIMIT</literal> clauses, care must be taken to control the locks acquired because of the order in which SQL expressions are evaluated. For example: 特に明示的な順序付けとLIMIT句を持つ問い合わせでは、この勧告ロックモードを使用する幾つかの場合において、SQL式が評価される順序を考慮し獲得されたロックを制御することに気を配らなければなりません。 以下に例を示します。


SELECT pg_advisory_lock(id) FROM foo WHERE id = 12345; &#45;- ok
SELECT pg_advisory_lock(id) FROM foo WHERE id &gt; 12345 LIMIT 100; &#45;- danger!
SELECT pg_advisory_lock(q.id) FROM
(
  SELECT id FROM foo WHERE id &gt; 12345 LIMIT 100
) q; &#45;- ok

SELECT pg_advisory_lock(id) FROM foo WHERE id = 12345; -- 問題なし
SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100; -- 危険!
SELECT pg_advisory_lock(q.id) FROM
(
  SELECT id FROM foo WHERE id > 12345 LIMIT 100
) q; -- 問題なし

In the above queries, the second form is dangerous because the <literal>LIMIT</literal> is not guaranteed to be applied before the locking function is executed. This might cause some locks to be acquired that the application was not expecting, and hence would fail to release (until it ends the session). From the point of view of the application, such locks would be dangling, although still viewable in <structname>pg_locks</structname>. 上の例では、ロック獲得関数が実行される前にLIMIT が適用されることを保障できないため、2番目の形式は危険です。 これにより、アプリケーションが想定していないなんらかのロックが生成される可能性があります。 そのため、(セッションが終了するまで)解放に失敗することになります。 アプリケーションから見ると、こうしたロックはただの飾りですが、pg_locksからは参照され続けます。

The functions provided to manipulate advisory locks are described in <xref linkend="functions-advisory-locks"/>. 勧告的ロックを扱うための関数については、9.27.10で説明します。