Lock:Relation
Lock:Relationイベントは、別のトランザクションによって現在ロックされているテーブルまたはビュー (リレーション) のロックを取得するためにクエリが待っているときに発生します。
サポート対象エンジンバージョン
この待機イベント情報は、Aurora PostgreSQL のすべてのバージョンでサポートされています。
Context
ほとんどの PostgreSQL コマンドは、テーブル内のデータへの同時アクセスを制御するために、暗黙のうちにロックを使用します。また、これらのロックは、アプリケーションコード内でLOCKコマンドによって明示的に使用することもできます。多くのロックモードは互いに互換性がないため、同じオブジェクトにアクセスしようとしているときにトランザクションをブロックすることがあります。これが起こると、Aurora 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 ドキュメントの「明示的なロック
ブロックされたクエリとトランザクションは、通常、次のいずれかの方法でブロックを解除します。
クエリのブロック: アプリケーションがクエリをキャンセルするか、ユーザーがプロセスを終了できます。また、セッションのステートメントタイムアウトやデッドロック検出メカニズムによって、エンジンがクエリを強制終了させることもできます。
トランザクションのブロック: トランザクションが
ROLLBACKまたはCOMMITを実行すると、トランザクションはブロックを停止します。ロールバックは、クライアントまたはネットワークの問題によってセッションが切断されたり、終了したときにも自動的に行われます。セッションは、データベースエンジンがシャットダウンされたり、システムがメモリ不足になったりしたときに終了できます。
待機時間が増加する原因の可能性
Lock:Relation イベントが通常よりも頻繁に発生する場合、パフォーマンスの問題を示している可能性があります。代表的な原因としては、以下が挙げられます。
- テーブルロックの競合による同時セッションの増加
-
競合するロックモードで同じテーブルをロックするクエリによる同時セッションの数が増加する可能性があります。
- メンテナンスオペレーション
-
VACUUMやANALYZEのようなヘルスメンテナンスオペレーションは、競合するロックの数を大幅に増加させる可能性があります。VACUUM FULLはACCESS EXCLUSIVEのロックを、ANALYZEはSHARE UPDATE EXCLUSIVEのロックを取得します。どちらのタイプのロックも、Lock:Relation待機イベントを引き起こすことがあります。また、マテリアライズドビューのリフレッシュなどのアプリケーションデータのメンテナンスオペレーションも、ブロックされたクエリとトランザクションを増加することもあります。 - リーダーインスタンスをロックする
-
ライターとリーダーが保持しているリレーションロックの間に矛盾がある可能性があります。現在は、
ACCESS EXCLUSIVEリレーションロックのみが、リーダーインスタンスにレプリケートされます。ただし、ACCESS EXCLUSIVEリレーションロックは、リーダーが保持するACCESS SHAREリレーションロックと競合します。これにより、リーダーのロックリレーション待機イベントが増加する可能性があります。
アクション
待機イベントの原因に応じたさまざまなアクションをお勧めします。
SQL ステートメントのブロックによる影響を軽減
SQL ステートメントのブロックによる影響を軽減するには、可能なところではアプリケーションコードを修正します。ブロックを減らすための 2 つの一般的な方法は以下のとおりです。
NOWAITオプションを使用する:SELECTやLOCKステートメントなど、一部の SQL コマンドはこのオプションをサポートしています。NOWAIT指示文は、ロックをすぐに取得できない場合、ロックへのクエリをキャンセルします。この方法は、ブロックされたセッションが、その後ろにあるブロックされたセッションが積み重なるのを防ぐのに役立ちます。例えば、トランザクション A がトランザクション B に保持されているロックを待っているとします。ここで、B がトランザクション C によってロックされているテーブルのロックをリクエストすると、トランザクション C が完了するまでトランザクション A がブロックされる可能性があります。ただし、トランザクション B が C のロックを要求するときに
NOWAITを使用する場合、トランザクションBは迅速に失敗し、トランザクション A が無期限に待機する必要がないことを保証できます。SET lock_timeoutを使用する:lock_timeout値を設定して、SQL ステートメントがリレーションでロックを取得するのを待機する時間を制限します。指定したタイムアウト時間内にロックが取得されなかった場合、ロックを要求したトランザクションはキャンセルされます。この値はセッションレベルで設定します。
メンテナンスオペレーションの影響を最小限に抑える
VACUUMやANALYZEのようなメンテナンスオペレーションは重要です。これらのメンテナンス作業に関連するLock:Relation待機イベントを見つけても、それらをオフにしないことをお勧めします。次のようなアプローチにより、これらの操作の影響を最小限に抑えることができます。
オフピーク時にメンテナンス操作をマニュアルで実行します。
オートバキュームタスクによる
Lock:Relation待機をへらすには、必要なオートバキュームチューニングを実行します。オートバキュームのチューニングについては、Amazon RDS ユーザーガイドの「Amazon RDS での PostgreSQL オートバキュームの使用」を参照してください。
リーダーロックをチェックする
ライターとリーダーの同時セッションが、お互いをブロックするロックを保持しているかどうかを確認できます。これを行う 1 つの方法は、ロックのタイプとリレーションを返すクエリを実行することです。この表では、ライターセッションとリーダーセッションという 2 つの同時セッションに対する一連のクエリを見つけることができます。
再生プロセスは、リーダークエリをキャンセルする前に max_standby_streaming_delay の期間待機します。例に示すように、100 ms のロックタイムアウトは、デフォルトの max_standby_streaming_delay である30 秒をはるかに下回っています。ロックは問題になる前にタイムアウトします。
| 一連のイベント | セッション | コマンドまたは出力 |
|---|---|---|
|
指定された値で READER という環境変数を設定し、このエンドポイントで DB インスタンスに接続しようとします。 |
リーダーセッション |
CLI コマンド:
出力: psql (15devel, server 10.14) Type "help" for help. |
|
WRITER という環境変数を設定し、このエンドポイントを使用して DB インスタンスに接続しようとします。 |
ライターセッション |
CLI コマンド:
出力: psql (15devel, server 10.14) Type "help" for help. |
|
ライターセッションはライターインスタンスにテーブル t1 を作成します。 |
ライターセッション |
PostgreSQL クエリ:
|
|
ライターに競合するクエリがない場合、ACCESS EXCLUSIVE ロックはライターですぐに取得されます。 |
ライターセッション |
|
|
リーダーセッションは 100 ミリ秒のロックタイムアウトインターバルを設定します。 |
リーダーセッション |
PostgreSQL クエリ:
|
|
リーダーセッションはリーダーインスタンスでテーブル t1 からデータを読み込もうとします。 |
リーダーセッション |
PostgreSQL クエリ:
サンプル出力: b --- (0 rows) |
|
ライターセッションが t1 をドロップします。 |
ライターセッション |
PostgreSQL クエリ:
|
|
クエリがタイムアウトし、リーダーでキャンセルされます。 |
リーダーセッション |
PostgreSQL クエリ:
サンプル出力: ERROR: canceling statement due to lock timeout
LINE 1: SELECT * FROM t1;
^
|
|
リーダーセッションが |
リーダーセッション |
PostgreSQL クエリ:
|
|
結果は、 |
リーダーセッション |
クエリ結果:
|