

# Lock:Relation
<a name="wait-event.lockrelation"></a>

`Lock:Relation`イベントは、別のトランザクションによって現在ロックされているテーブルまたはビュー (リレーション) のロックを取得するためにクエリが待っているときに発生します。

**Topics**
+ [サポート対象エンジンバージョン](#wait-event.lockrelation.context.supported)
+ [Context](#wait-event.lockrelation.context)
+ [待機時間が増加する原因の可能性](#wait-event.lockrelation.causes)
+ [アクション](#wait-event.lockrelation.actions)

## サポート対象エンジンバージョン
<a name="wait-event.lockrelation.context.supported"></a>

この待機イベント情報は、RDS for PostgreSQL のすべてのバージョンでサポートされています。

## Context
<a name="wait-event.lockrelation.context"></a>

ほとんどの PostgreSQL コマンドは、テーブル内のデータへの同時アクセスを制御するために、暗黙のうちにロックを使用します。また、これらのロックは、アプリケーションコード内で`LOCK`コマンドによって明示的に使用することもできます。多くのロックモードは互いに互換性がないため、同じオブジェクトにアクセスしようとしているときにトランザクションをブロックすることがあります。このイベントが発生すると、RDS for PostgreSQL は `Lock:Relation` イベントを生成します。一般的な例をいくつか以下に示します。
+ `ACCESS EXCLUSIVE`のような排他的なロックは、すべての同時アクセスをブロックできます。`DROP TABLE`、`TRUNCATE`、`VACUUM FULL`、`CLUSTER`などのデータ定義言語 (DDL) オペレーションは、暗黙のうちに`ACCESS EXCLUSIVE`ロックを取得します。`ACCESS EXCLUSIVE` は、明示的にモードを指定しない `LOCK TABLE` ステートメントのデフォルトのロックモードでもあります。
+ テーブル上で`CREATE INDEX (without CONCURRENT)`を使用すると、`ROW EXCLUSIVE`ロックを取得するデータ操作言語 (DML) ステートメント`UPDATE`、`DELETE`、`INSERT`と競合します。

テーブルレベルのロックと競合するロックモードの詳細については、PostgreSQL ドキュメントの「[明示的なロック](https://www.postgresql.org/docs/13/explicit-locking.html)」を参照してください。

ブロックされたクエリとトランザクションは、通常、次のいずれかの方法でブロックを解除します。
+ クエリのブロック: アプリケーションがクエリをキャンセルするか、ユーザーがプロセスを終了できます。また、セッションのステートメントタイムアウトやデッドロック検出メカニズムによって、エンジンがクエリを強制終了させることもできます。
+ トランザクションのブロック: トランザクションが `ROLLBACK` または `COMMIT` を実行すると、トランザクションはブロックを停止します。ロールバックは、クライアントまたはネットワークの問題によってセッションが切断されたり、終了したときにも自動的に行われます。セッションは、データベースエンジンがシャットダウンされたり、システムがメモリ不足になったりしたときに終了できます。

## 待機時間が増加する原因の可能性
<a name="wait-event.lockrelation.causes"></a>

`Lock:Relation` イベントが通常よりも頻繁に発生する場合、パフォーマンスの問題を示している可能性があります。代表的な原因としては、以下が挙げられます。

**テーブルロックの競合による同時セッションの増加**  
競合するロックモードで同じテーブルをロックするクエリによる同時セッションの数が増加する可能性があります。

**メンテナンスオペレーション**  
`VACUUM`や`ANALYZE`のようなヘルスメンテナンスオペレーションは、競合するロックの数を大幅に増加させる可能性があります。`VACUUM FULL`は`ACCESS EXCLUSIVE`のロックを、`ANALYSE`は`SHARE UPDATE EXCLUSIVE`のロックを取得します。どちらのタイプのロックも、`Lock:Relation`待機イベントを引き起こすことがあります。また、マテリアライズドビューのリフレッシュなどのアプリケーションデータのメンテナンスオペレーションも、ブロックされたクエリとトランザクションを増加することもあります。

**リーダーインスタンスをロックする**  
ライターとリーダーが保持しているリレーションロックの間に矛盾がある可能性があります。現在は、`ACCESS EXCLUSIVE` リレーションロックのみが、リーダーインスタンスにレプリケートされます。ただし、`ACCESS EXCLUSIVE` リレーションロックは、リーダーが保持する `ACCESS SHARE` リレーションロックと競合します。これにより、リーダーのロックリレーション待機イベントが増加する可能性があります。

## アクション
<a name="wait-event.lockrelation.actions"></a>

待機イベントの原因に応じたさまざまなアクションをお勧めします。

**Topics**
+ [SQL ステートメントのブロックによる影響を軽減](#wait-event.lockrelation.actions.reduce-blocks)
+ [メンテナンスオペレーションの影響を最小限に抑える](#wait-event.lockrelation.actions.maintenance)

### SQL ステートメントのブロックによる影響を軽減
<a name="wait-event.lockrelation.actions.reduce-blocks"></a>

SQL ステートメントのブロックによる影響を軽減するには、可能なところではアプリケーションコードを修正します。ブロックを減らすための 2 つの一般的な方法は以下のとおりです。
+ `NOWAIT` オプションを使用する: `SELECT` や `LOCK` ステートメントなど、一部の SQL コマンドはこのオプションをサポートしています。`NOWAIT`指示文は、ロックをすぐに取得できない場合、ロックへのクエリをキャンセルします。この方法は、ブロックされたセッションが、その後ろにあるブロックされたセッションが積み重なるのを防ぐのに役立ちます。

  例えば、トランザクション A がトランザクション B に保持されているロックを待っているとします。ここで、B がトランザクション C によってロックされているテーブルのロックをリクエストすると、トランザクション C が完了するまでトランザクション A がブロックされる可能性があります。ただし、トランザクション B が C のロックを要求するときに`NOWAIT`を使用する場合、トランザクションBは迅速に失敗し、トランザクション A が無期限に待機する必要がないことを保証できます。
+ `SET lock_timeout` を使用する: `lock_timeout` 値を設定して、SQL ステートメントがリレーションでロックを取得するのを待機する時間を制限します。指定されたタイムアウト時間内にロックが取得されなかった場合、ロックを要求したトランザクションはキャンセルされます。この値はセッションレベルで設定します。

### メンテナンスオペレーションの影響を最小限に抑える
<a name="wait-event.lockrelation.actions.maintenance"></a>

`VACUUM`や`ANALYZE`のようなメンテナンスオペレーションは重要です。これらのメンテナンス作業に関連する`Lock:Relation`待機イベントを見つけても、それらをオフにしないことをお勧めします。次のようなアプローチにより、これらの操作の影響を最小限に抑えることができます。
+ オフピーク時にメンテナンス操作をマニュアルで実行します。
+ オートバキュームタスクによる`Lock:Relation`待機をへらすには、必要なオートバキュームチューニングを実行します。オートバキュームのチューニングについては、*Amazon RDS ユーザーガイド*の「[Amazon RDS での PostgreSQL オートバキュームの使用](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html)」を参照してください。