Lock:tuple
Lock:tuple
イベントは、バックエンドプロセスがタプルのロックを取得するのを待っているときに発生します。
サポート対象エンジンバージョン
この待機イベント情報は、RDS for PostgreSQL のすべてのバージョンでサポートされています。
Context
イベントLock:tuple
は、バックエンドがタプルのロック取得を待っている間、別のバックエンドが同じタプルで競合するロックを保持していることを示します。次の表では、セッションがLock:tuple
イベントを生成するシナリオを示します。
時間 |
セッション 1 |
セッション 2 |
セッション 3 |
---|---|---|---|
t1 |
トランザクションをスタートします。 |
||
t2 |
行 1 を更新します。 |
||
t3 |
行 1 を更新します。セッションは、タプルの排他ロックを取得してから、セッション1がコミットまたはロールバックによってロックを解放するのを待機します。 |
||
t4 |
行 1 を更新します。セッションは、セッション 2 がタプルの排他ロックを解放するのを待機します。 |
または、ベンチマークツールpgbench
を使用してこの待機イベントをシミュレートすることができます。多数の同時セッションを構成して、カスタムSQLファイルでテーブル内の同じ行を更新します。
競合するロックモードの詳細については、「PostgreSQL のドキュメント」の「明示的なロックpgbench
の詳細については、「PostgreSQL のドキュメント」の「pgbench
待機時間が増加する原因の可能性
このイベントが通常よりも頻繁に表示される場合、パフォーマンスの問題を示している可能性があり、典型的な原因は次のとおりです。
-
UPDATE
またはDELETE
ステートメントの実行により、同じタプルへの競合するロックを取得しようとしている同時セッションが多数あります。 -
同時実行数の多いセッションでは、
FOR UPDATE
またはFOR NO KEY UPDATE
ロックモードを使用してSELECT
ステートメントを実行します。 -
さまざまな要因により、アプリケーションまたは接続プールが同じオペレーションを実行するため、より多くのセッションを開きます。新しいセッションが同じ行を変更しようとすると、DB ロードのスパイクが発生して
Lock:tuple
が表示されることがあります。
詳細については、「PostgreSQL のドキュメント」の「行レベルのロック
アクション
待機イベントの原因に応じたさまざまなアクションをお勧めします。
アプリケーションロジックを調査する
ブロッカーセッションが長い間idle in
transaction
ステートメントにあったかどうかを確認します。その場合は、短期的な解決策としてブロッカーセッションの終了を検討してください。pg_terminate_backend
関数を使用することもできます。この関数の詳細については、「PostgreSQL のドキュメント」の「サーバーシグナリング関数
長期的な解決策としては、以下を実行してください。
-
アプリケーションロジックを調整します。
-
idle_in_transaction_session_timeout
パラメータを使用します。このパラメータは、指定された時間より長くアイドル状態であったオープントランザクションを持つセッションを終了させます。詳細については、PostgreSQL ドキュメントの 「Client Connection Defaults (クライアント接続のデフォルト)」 を参照してください。 -
可能な限りオートコミットを使用します。詳細については、PostgreSQL ドキュメントの 「Client authentication (クライアント認証)
」 を参照してください。
ブロッカーセッションを見つける
Lock:tuple
の待機イベントが発生している間に、どのロックが互いに依存しているかを探して、ブロッカーとブロックされたセッションを特定します。詳細については、PostgreSQL wiki にの「依存関係情報のロック
次の例では、tuple
でフィルタリングしてwait_time
で順序付けし、すべてのセッションへのクエリを実行しています。
SELECT blocked_locks.pid AS blocked_pid, blocking_locks.pid AS blocking_pid, blocked_activity.usename AS blocked_user, blocking_activity.usename AS blocking_user, now() - blocked_activity.xact_start AS blocked_transaction_duration, now() - blocking_activity.xact_start AS blocking_transaction_duration, concat(blocked_activity.wait_event_type,':',blocked_activity.wait_event) AS blocked_wait_event, concat(blocking_activity.wait_event_type,':',blocking_activity.wait_event) AS blocking_wait_event, blocked_activity.state AS blocked_state, blocking_activity.state AS blocking_state, blocked_locks.locktype AS blocked_locktype, blocking_locks.locktype AS blocking_locktype, blocked_activity.query AS blocked_statement, blocking_activity.query AS blocking_statement FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid AND blocking_locks.pid != blocked_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_locks.GRANTED;
同時実行数が多いときにそれを減らす
Lock:tuple
イベントは、特にワークロードの多い時間帯に、コンスタントに発生する可能性があります。このような状況では、非常にビジーな行への同時実行数を減らすことを検討してください。多くの場合、キューまたはブールロジックを制御する行の数行だけで、これらの行は非常にビジーになります。
ビジネス要件、アプリケーションロジック、およびワークロードタイプに応じて、さまざまなアプローチを使用することで、競合を減らすことができます。例えば、次のオペレーションを実行できます。
-
テーブルとデータロジックを再設計し、競合を減らします。
-
アプリケーションロジックを変更して、行レベルで高い競合を減らします。
-
行レベルのロックを活用してクエリを再設計します。
-
NOWAIT
節はリトライオペレーションで使用します。 -
楽観的かつハイブリッドロックロジックの同時実行制御の使用を検討します。
-
データベースの隔離レベルの変更を検討してください。
ボトルネックのトラブルシューティング
Lock:tuple
は、CPU の枯渇や Amazon EBS 帯域幅の最大使用率などのボトルネックを発生させることがあります。ボトルネックを減らすには、次のアプローチを検討します。
-
インスタンスクラスタイプをスケールアップします。
-
リソースを大量に消費するクエリを最適化します。
-
アプリケーションロジックを変更します。
-
ほとんどアクセスされないデータをアーカイブします。