ロックを理解する
マルチバージョン コンカレンシー制御 (MVCC) は、ほとんどのシナリオに適したコンカレンシー設定を提供します。 ただし、影響を受ける行と特定のロック レベルを正確に制御する特定のロックがアプリケーションに必要な場合は、明示的なロック モードによって、このきめ細かい制御が有効になります。
Azure Database for PostgreSQL には、明示的なロック、テーブル レベルのロック、行レベルのロック、ページ レベルのロックの 3 種類があります。 最初のトランザクションはロックを要求し、受け入れられた場合は、要求されたロックが既存のロックになります。 別のトランザクションが同じデータに対してロックを解除しようとすると、元のトランザクションと競合しない場合、ロックが付与されます。
たとえば、2 つのトランザクションで、SELECT ステートメントを使用して同じデータに対して同時にクエリを実行できます。 これらの要求では ACCESS SHARE ロックが使用され、両方とも許可されます。 別のシナリオでは、あるトランザクションが SELECT ステートメントと ACCESS SHARE ロックを使用してデータに対してクエリを実行していますが、同時に、別のトランザクションが同じテーブルを削除しようとします。 テーブルを削除するには、このシナリオでは許可されない ACCESS EXCLUSIVE ロックが必要です。
テーブルレベルのロック
テーブル レベルのロックは、名前に ROW がある場合でも、テーブル全体のロックを取得します。 テーブル自体が変更されている場合は、テーブル全体のロックが必要になる場合や、多くの行レベルのロックを取り出すよりも効率的な場合があります。
Azure Database for PostgreSQL には 8 種類のテーブル レベルロックがあり、これらの種類のロックを取得する SQL コマンドは次のとおりです。
| ロック モード | 取得方法 |
|---|---|
| ACCESS SHARE | SELECT コマンド |
| ROW SHARE | SELECT FOR UPDATE および SELECT FOR SHARE コマンド |
| ROW EXCLUSIVE | UPDATE、DELETE、INSERT の各コマンド |
| SHARE UPDATE EXCLUSIVE | ANALYZE、CREATE INDEX CONCURRENTLY、CREATE STATISTICS、COMMENT ON、REINDEX CONCURRENTLY コマンド、一部の ALTER INDEX および ALTER TABLE コマンド、VACUUM (FULL ではない) |
| SHARE | CREATE INDEX (CONCURRENTLY ではない) コマンド |
| SHARE ROW EXCLUSIVE | CREATE TRIGGER コマンドと一部の ALTER TABLE コマンド |
| EXCLUSIVE | REFRESH MATERIALIZED VIEW CONCURRENTLY コマンド |
| アクセス限定 | DROP TABLE、REINDEX、TRUNCATE、CLUSTER、REFRESH MATERIALIZED VIEW (CONCURRENTLY ではない) コマンド、ほとんどの ALTER INDEX および ALTER TABLE コマンド、VACUUM FULL |
既存のロックの各種類は、他の要求されたロックの取得をブロックします。 次の表に、他のロックの取得をブロックするロックを示します。
| -- | 既存の ACCESS SHARE | 既存の ROW SHARE | 既存の ROW EXCLUSIVE | 既存の SHARE UPDATE EXCLUSIVE | 既存の SHARE | 既存の SHARE ROW EXCL | 既存の EXCLUSIVE | 既存の ACCESS EXCLUSIVE |
|---|---|---|---|---|---|---|---|---|
| 要求された ACCESS SHARE | ブロックされました | |||||||
| 要求された ROW SHARE | ブロックされました | ブロックされました | ||||||
| 要求された ROW EXCLUSIVE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ||||
| 要求された SHARE UPDATE EXCLUSIVE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | |||
| 要求された SHARE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | |||
| 要求された SHARE ROW EXCLUSIVE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ||
| 要求された EXCLUSIVE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | |
| 要求された ACCESS EXCLUSIVE | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました | ブロックされました |
行レベルのロック
行レベルのロックはより細かく、同じ行にアクセスしている別のトランザクションにのみ影響します。 このロックの種類によりコンカレンシーが向上しますが、多くのロックを取得および削除すると、パフォーマンスに悪影響が及びます。 行レベルのロックは PostgreSQL によって自動的に取得され、手動では適用されません。
Azure Database for PostgreSQL には 4 種類の行レベル ロックがあり、ブロックする必要がある他のロックの種類に応じて取得されます。
| -- | 既存の FOR KEY SHARE | 既存の FOR SHARE | 既存の FOR NO KEY UPDATE | 既存の FOR UPDATE |
|---|---|---|---|---|
| キー共有のためにリクエストされました | ブロックされました | |||
| 要求された FOR SHARE | ブロックされました | ブロックされました | ||
| 要求された FOR NO KEY UPDATE | ブロックされました | ブロックされました | ブロックされました | |
| 要求された FOR UPDATE | ブロックされました | ブロックされました | ブロックされました | ブロックされました |
ページ レベルのロック
ページ レベルのロックは、通常は複数の行で構成されるデータのページに影響します。 PostgreSQL プロセスではページ レベルのロックが使用されますが、通常、アプリケーション開発者はこの種類のロックを必要としません。
ロックの手動適用と現在のロックの表示
テーブル レベルのロックを手動で適用するには、LOCK コマンドを必要なロック モードで使用します。 LOCK コマンドはトランザクション内に存在する必要があり、トランザクションの完了時にロックが解放されます。 例えば次が挙げられます。
BEGIN TRANSACTION;
LOCK TABLE humanresources.department IN ROW EXCLUSIVE MODE;
COMMIT;
データベースで現在保持されているロックを表示するには、 pg_locksを使用します。 たとえば、現在のすべてのロックを表示するには、次のコマンドを使用します。
SELECT * FROM pg_locks;