次の方法で共有


最適化されたロック

適用対象: SQL Server 2025 (17.x) Azure SQL DatabaseAzure SQL Managed InstanceMicrosoft Fabric 内の SQL データベース

最適化されたロックにより、トランザクション ロック メカニズムが強化され、同時トランザクションのロック ブロックとロック メモリの消費量が削減されます。

最適化されたロックとは

最適化ロックは、大規模なトランザクションでも保持されるロックの数が非常に少ないため、ロック メモリの使用を削減するのに役立ちます。 さらに、最適化されたロックはロックのエスカレーションを回避し、特定の種類のデッドロックを回避できます。 これにより、テーブルへの同時アクセスが増えます。

最適化されたロックは、トランザクション ID (TID) のロック修飾後ロック (LAQ) の 2 つの主要コンポーネントで構成されます。

  • トランザクション ID (TID) は、トランザクションの一意の識別子です。 各行には、最後に変更された TID のラベルが付けられます。 キーまたは行識別子のロックが多くなる可能性がある代わりに、変更されたすべての行を保護するために、TID の 1 つのロックが使用されます。 詳細については、「トランザクション ID (TID) ロック」を参照してください。
  • 修飾後のロック (LAQ) は、ロックを取得せずに、最新のコミット済みバージョンの行に対するクエリの述語を評価する最適化であり、コンカレンシーを向上させます。 LAQ には読み取りコミット済みスナップショット分離 (RCSI)が必要です。 詳細については、「修飾後のロック (LAQ)」を参照してください。

例えば次が挙げられます。

  • 最適化されたロックを使用しない場合、テーブル内の 1,000 行を更新するには、トランザクションの終了まで保持される 1,000 個の排他 (X) 行ロックが必要になる可能性があります。
  • 最適化されたロックでは、テーブル内の 1,000 行を更新するには 1,000 X 行ロックが必要になる場合がありますが、各行が更新されるとすぐに各ロックが解放され、トランザクションの終了時まで保持される X TID ロックは 1 つだけです。 ロックは迅速に解放されるため、ロック メモリの使用量が減り、ロックのエスカレーションが発生する可能性が大幅に低くなり、ワークロードのコンカレンシーが向上します。

Note

最適化されたロックを有効にすると、データ変更言語 (DML) ステートメント ( INSERTUPDATEDELETEMERGEなど) によって取得される行およびページのロックが減少または排除されます。 スキーマ ロックなど、他の種類のデータベース ロックやオブジェクト ロックには影響しません。

Availability

次の表は、SQL プラットフォーム間での最適化されたロックの可用性と有効な状態をまとめたものです。

Platform Available 既定で有効
Azure SQL Database Yes はい (常に有効)
Microsoft Fabric の SQL データベース Yes はい (常に有効)
Azure SQL Managed InstanceAUTD Yes はい (常に有効)
Azure SQL Managed Instance2025 Yes はい (常に有効)
Azure SQL Managed Instance2022 No N/A
SQL Server 2025 (17.x) Yes いいえ (データベースごとに有効にできます)
SQL Server 2022 (16.x) 以前のバージョン No N/A

有効化と無効化

SQL Server データベースの最適化されたロックを有効または無効にするには、 ALTER DATABASE ... SET OPTIMIZED_LOCKING = ON | OFF コマンドを使用します。 詳細については、ALTER DATABASE SET オプションに関するページを参照してください。

最適化されたロックは、他のデータベース機能に基づいて構築されます。

  • 最適化されたロックを有効にするには、データベースで 高速データベース復旧 (ADR) を有効にする必要があります。 逆に、ADR を無効にするには、最適化されたロックが有効になっている場合は、最初に無効にする必要があります。
  • 最適化されたロックの利点を最大限に活用するには、データベースに対して 読み取りコミット済みスナップショット分離 (RCSI) を有効にする必要があります。 最適化されたロックの LAQ コンポーネントは、RCSI が有効になっている場合にのみ有効です。

ADR は、Azure SQL Database、Azure SQL Managed Instance、および Microsoft Fabric の SQL データベースで常に有効になります。 RCSI は、Azure SQL Database と Microsoft Fabric の SQL データベースで既定で有効になっています。

これらのオプションが現在のデータベースで有効になっていることを確認するには、データベースに接続し、次の T-SQL クエリを実行します。

SELECT database_id,
       name,
       is_accelerated_database_recovery_on,
       is_read_committed_snapshot_on,
       is_optimized_locking_on
FROM sys.databases
WHERE name = DB_NAME();

最適化されたロックは有効になっていますか?

最適化されたロックはデータベースごとに有効になります。 データベースに接続し、次のクエリを使用して、データベースで最適化されたロックが有効になっているかどうかを確認します。

SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_enabled;
Result Description
0 最適化されたロックが無効になっています。
1 最適化されたロックが有効になっています。
NULL 最適化されたロックは使用できません。

sys.databases カタログ ビューを使用することもできます。 たとえば、すべてのデータベースに対して最適化されたロックが有効になっているかどうかを確認するには、次のクエリを実行します。

SELECT database_id,
       name,
       is_optimized_locking_on
FROM sys.databases;

ロックの概要

これは、最適化されたロックが有効になっていない場合の動作の簡単な概要です。 詳細については、「トランザクションのロックおよび行のバージョン管理ガイド」を参照してください。

データベース エンジンにおけるロックとは、トランザクションの ACID プロパティを保証するために、複数のトランザクションが同じデータを同時に更新することを防ぐメカニズムです。

トランザクションでデータを変更する必要がある場合は、データのロックを要求します。 データに対して他の競合するロックが保持されておらず、トランザクションが変更を続行できる場合は、ロックが付与されます。 データに対して別の競合するロックが保持されている場合、トランザクションはロックが解放されるのを待ってから続行する必要があります。

複数のトランザクションが同じデータに同時にアクセスしようとすると、同時読み取りと同時書き込みによる複雑な競合が発生する可能性があり、データベース エンジンでそれを解決する必要があります。 ロックは、エンジンが ANSI SQL トランザクション分離レベルのセマンティクスを提供できるメカニズムの 1 つです。 データベースのロックは不可欠ですが、コンカレンシー、デッドロック、複雑さ、ロックのオーバーヘッドの低下は、パフォーマンスとスケーラビリティに影響する可能性があります。

トランザクション ID (TID) のロック

行のバージョン管理ベースの分離レベルが使用されている場合、または ADR が有効になっている場合、データベース内のすべての行に内部的にトランザクション ID (TID) が含まれます。 TID は行と共に保持されます。 行を変更するすべてのトランザクションでは、その行に TID がスタンプされます。

TID ロック化では、行のキーをロックする代わりに、行の TID に対してロックが行われます。 変更中のトランザクションは、TID に対して X ロックを保持します。 その他のトランザクションは、TID に対する S ロックを取得し、最初のトランザクションが完了するまで待機します。 TID ロックでは、変更のためにページ ロックと行ロックが引き続き取得されますが、各ページ ロックと行ロックは各行が変更されるとすぐに解放されます。 トランザクションが終了するまで保持される唯一のロックは、複数のページロックと行 (キー) ロックを置き換える TID リソースの X ロックです。

書き込みトランザクションがアクティブな間の現在のセッションのロックを示す、次の例を考えてみましょう。

/* Is optimized locking is enabled? */
SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_enabled;

CREATE TABLE t0
(
a int PRIMARY KEY,
b int NULL
);

INSERT INTO t0 VALUES (1,10),(2,20),(3,30);
GO

BEGIN TRANSACTION;

UPDATE t0
SET b = b + 10;

SELECT *
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
      AND
      resource_type IN ('PAGE','RID','KEY','XACT');

COMMIT TRANSACTION;
GO

DROP TABLE IF EXISTS t0;

最適化されたロックが有効になっている場合、要求は、X (トランザクション) リソースに対して 1 つの XACT ロックのみを保持します。

単一セッションの sys.dm_tran_locks に対するクエリの結果セットのスクリーンショット。最適化されたロックが有効な場合はロックが 1 つだけ表示されます。

最適化されたロックが有効になっていない場合、同じ要求は 4 つのロック (行を含むページに対して 1 つの IX (意図排他) ロック、各行に 3 つの X キー ロック) を保持します。

単一セッションの sys.dm_tran_locks に対するクエリの結果セットのスクリーンショット。最適化されたロックが有効ではない場合はロックが 3 つ表示されます。

sys.dm_tran_locks動的管理ビュー (DMV) は、ロックの問題の調査またはトラブルシューティングに役立ちます。 ここでは、動作中の最適化されたロックを観察するために使用されます。

修飾後ロック (LAQ)

TID インフラストラクチャを基盤として、最適化されたロックの LAQ コンポーネントによって、 INSERTUPDATEDELETE などの DML ステートメントがロックを取得する方法が変わります。

最適化されたロックを使用しない場合、最初に更新 (U) 行ロックを取得することで、クエリ述語がスキャンで行ごとにチェックされます。 述語が満たされている場合、行を更新する前に排他的 (X) 行ロックが取得され、トランザクションが終了するまで保持されます。

最適化されたロックを使用すると、 READ COMMITTED スナップショット分離レベル (RCSI) が有効になっている場合、ロックを取ることなく、行の最新のコミット済みバージョンで述語をオプティミスティックにチェックできます。 述語が満たされない場合、クエリはスキャンの次の行に移動します。 述語が満たされている場合は、行を更新するために X 行ロックが取得されます。

つまり、変更する行の "修飾後" にロックが取得されます。 X 行ロックは、トランザクションの終了前に行の更新が完了するとすぐに解放されます。

述語の評価はロックを取得せずに実行されるため、異なる行を変更する同時クエリが相互にブロックされることはありません。

例えば次が挙げられます。

/* Confirm that optimized locking and read committed snapshot isolation (RCSI) are both enabled on this database. */
SELECT database_id,
       name,
       is_accelerated_database_recovery_on,
       is_optimized_locking_on,
       is_read_committed_snapshot_on
FROM sys.databases
WHERE name = DB_NAME();

CREATE TABLE t1
(
a int NOT NULL,
b int NULL
);

INSERT INTO t1
VALUES (1,10),(2,20),(3,30);
GO
セッション 1 セッション 2
BEGIN TRANSACTION;
UPDATE t1
SET b = b + 10
WHERE a = 1;
BEGIN TRANSACTION;
UPDATE t1
SET b = b + 10
WHERE a = 2;
COMMIT TRANSACTION;
COMMIT TRANSACTION;

セッション 1 は行セッション 2 の更新が必要な U ロックを保持しているため、最適化されたロックがないとセッション 2 はブロックされます。 一方、最適化されたロックを使用する場合、セッション 2 はブロックされません。これは、U ロックが取得されておらず、最新のコミットされたバージョンの行 1 の列 a が 1 と等しい (セッション 2 の述語を満たしていない) からです。

LAQ は、述語をチェックした後に行が変更されないという前提で、楽観的に実行されます。 述語が満たされ、述語の確認後も行が変更されていなければ、それは現在のトランザクションによって変更されます。

U ロックが取得されていないため、述語を評価した後に同時実行トランザクションによって行が変更される可能性があります。 行に対する X TID ロックを保持しているアクティブなトランザクションがある場合、データベース エンジンは完了を待機します。 述語が以前に評価された後に行が変更された場合、データベース エンジンは、行を変更する前に述語をもう一度再評価 (再修飾) します。 述語がまだ満たされている場合は、行が変更されます。

述語の再修飾は、クエリ エンジン演算子のサブセットによってサポートされます。 述語の再評価が必要であっても、クエリ プランで述語の再修飾をサポートしていない演算子が使用されている場合、データベース エンジンは内部的にステートメント処理を中止し、LAQ なしで再開します。 このような中止が発生すると、lock_after_qual_stmt_abort 拡張イベントが発生します。

一部のステートメント (たとえば、変数の代入 UPDATE ステートメント、 OUTPUT 句を使用したステートメントなど) は、セマンティクスを変更しないと中止および再開できません。 このようなステートメントでは、LAQ は使用されません。

次の例では、別のトランザクションによって行が変更されたため、述語が再評価されます。

CREATE TABLE t3
(
a int NOT NULL,
b int NULL
);

INSERT INTO t3 VALUES (1,10),(2,20),(3,30);
GO
セッション 1 セッション 2
BEGIN TRANSACTION;
UPDATE t3
SET b = b + 10
WHERE a = 1;
BEGIN TRANSACTION;
UPDATE t3
SET b = b + 10
WHERE a = 1;
COMMIT TRANSACTION;
COMMIT TRANSACTION;

インデックス ロックをスキップする (SIL)

TID ロックでは、短い期間の排他 (X) 行ロックと意図排他 (IX) ページ ロックが行の変更に使用されます。 RCSI と LAQ を使用する場合、これらのロックは、行にアクセスする他のクエリがあり、それが安定していることを予期している場合にのみ必要です。 このようなクエリの例としては、 REPEATABLE READ または SERIALIZABLE 分離レベルで実行されているクエリや、対応するロック ヒントの使用があります。 このようなクエリは 、行ロック クエリ (RLQ) と呼ばれます。

行にアクセスする RLQ クエリがない場合、データベース エンジンは行の変更時に行ロックとページ ロックの取得をスキップでき、排他ページ ラッチのみを使用できます。 この最適化により、ACID トランザクション セマンティクスを維持しながら、ロックのオーバーヘッドが軽減されます。 行ロックとページ ロックをスキップすると、トランザクションが多数の行を変更する場合に特に便利です。

現在、SIL 最適化は次の場合にのみ使用されます。

  • INSERT ヒープに関するステートメント。
    • IX ページ ロックはスキップされます。
  • UPDATE クラスター化インデックス、非クラスター化インデックス、ヒープに対するステートメント。
    • IX ページ ロックと X 行ロックはスキップされます。

次の場合、SIL 最適化は現在使用されていません。

  • DELETE ステートメント。
  • UPDATE 行に既存の転送ポインターが含まれている場合、または更新によって新しい転送ポインターが追加された場合は、ヒープ上のステートメント。
  • 変更された行に、 varchar(max)nvarchar(max)varbinary(max)jsonなどの LOB データ型を使用する列がある場合。
  • 同じトランザクションで分割されたページ上の行の場合。

LAQ ヒューリスティック

修飾 後のロック (LAQ) で説明されているように、LAQ を使用すると、述語の再修飾をサポートしないクエリ演算子を使用するステートメントが内部的に再起動され、LAQ なしで処理される可能性があります。 これが頻繁に発生する場合、再処理のオーバーヘッドが大きくなる可能性があります。 オーバーヘッドを最小限に抑えるために、最適化されたロックでは、オーバーヘッドがしきい値を超えた場合に LAQ を無効にするヒューリスティック ベースのフィードバック メカニズムが使用されます。

フィードバック メカニズムの目的上、ステートメントによって実行される作業は、論理読み取りの数で測定されます。 ステートメント処理の開始後にデータベース エンジンが別のトランザクションによって変更された行を変更している場合、ステートメントの処理は、ステートメントの再処理が必要になる可能性があるため、無駄になる可能性があると見なされます。

ステートメントが実行されると、データベース エンジンは、無駄になる可能性のある作業、ステートメントの再処理の発生、および再処理される可能性があるステートメントによって実行された合計作業を追跡する LAQ フィードバック データを保持します。

LAQ は、無駄になる可能性のある作業の合計作業時間に対する割合、またはステートメントの合計数に対する再処理されたステートメントの数の比率がそれぞれのしきい値を超えた場合に無効になります。 これらの両方の比率がしきい値を下回った場合、LAQ は再び有効になります。

LAQ フィードバック データは、次の 2 つのレベルで追跡されます。

  • クエリプランの場合。

    • データベース エンジンは、ステートメントの再処理が最初に発生した場合に、計画の LAQ フィードバックの追跡を開始します。
    • クエリがクエリ ストアでキャプチャされた場合、LAQ フィードバックもクエリ ストアにキャプチャされます。 データベース エンジンは、このフィードバックを使用して、データベースが再起動された場合に、LAQ をプランに対して有効または無効のままにします。
    • キャプチャされた LAQ フィードバックを含むクエリ プランには、plan_idに一致する値を持つ行があります。 feature_id 列と feature_desc 列は 4 と LAQ Feedback にそれぞれ設定されています。
  • データベースの場合。

    • クエリ がクエリ ストアにキャプチャされていない場合など、クエリ プラン レベルのフィードバックがないすべてのステートメントについて、フィードバックが集計されます。
    • フィードバックはデータベースの起動以降に追跡され、各スタートアップ後に再作成されます。

ステートメントに LAQ を使用するかどうかを決定する場合、システムはクエリ プランのフィードバック (使用可能な場合) を使用します。 それ以外の場合は、データベース レベルのフィードバックが使用されます。 つまり、一部のステートメントは LAQ で実行され、一部のステートメントは LAQ なしで実行される可能性があります。 たとえば、クエリ プランでは LAQ が無効になっていても、データベースに対して有効になっている場合や、データベースに対して LAQ が有効になっている場合などです。

LAQ の制限事項

資格後のロックは、次のシナリオでは使用されません。

  • LAQ ヒューリスティックによって無効にされた場合。
  • UPDLOCKREADCOMMITTEDLOCKXLOCKHOLDLOCKなど、ロック ヒントが競合する場合に使用されます。
  • トランザクション分離レベルが READ COMMITTED以外の場合、または READ_COMMITTED_SNAPSHOT データベース オプションが無効になっている場合。
  • 変更対象のテーブルに列ストア インデックスがある場合。
  • DML ステートメントに変数の代入が含まれている場合。
  • DML ステートメントに OUTPUT 句がある場合。
  • DML ステートメントで複数のインデックス シークまたはスキャン演算子を使用して、変更されている行を読み取る場合。
  • MERGE でのステートメント

最適化されたロックと RCSI によるクエリ動作変更

トランザクションの厳密な実行順序に依存する読み取りコミット スナップショット分離 (RCSI) の同時実行ワークロードでは、最適化されたロックが有効になっている場合、クエリのビヘイビアーに違いが生じる可能性があります。

トランザクション T2 がトランザクション T1 中に更新された列 t4 に基づいたテーブル b を更新する例を次に示します。

CREATE TABLE t4
(
a int NOT NULL,
b int NULL
);

INSERT INTO t4
VALUES (1,1);
GO
セッション 1 セッション 2
BEGIN TRANSACTION T1;
UPDATE t4
SET b = 2
WHERE a = 1;
BEGIN TRANSACTION T2;
UPDATE t4
SET b = 3
WHERE b = 2;
COMMIT TRANSACTION;
COMMIT TRANSACTION;

前のシナリオの結果を、適格性判断後のロック (LAQ) の有無にかかわらず評価してみましょう。

LAQ なし

LAQ がない場合、トランザクション T2 の UPDATE ステートメントはブロックされ、トランザクション T1 が完了するまで待機します。 T1 が完了すると、T2 は述語が満たされるため、行設定列 b3 に更新します。

両方のトランザクションがコミットされると、テーブル t4 には次の行が含まれます。

 a | b
 1 | 3

LAQ の場合

LAQ では、トランザクション T2 は、列 b1 と等しい行の最新のコミット済みバージョンを使用して、述語 (b = 2) を評価します。 行は条件を満たしていないため、トランザクション T1 によってブロックされることなく省略され、ステートメントは完了します。 この例では、LAQ はブロッキングを削除しますが、結果が異なります。

両方のトランザクションがコミットされると、テーブル t4 には次の行が含まれます。

 a | b
 1 | 2

Important

LAQ がない場合でも、行のバージョン管理ベースの分離レベルを使用する場合、ロック ヒントを使用せずにデータベース エンジンが厳密な順序付けを保証することをアプリケーションで想定しないでください。 (前の演習で示したように)、トランザクションの厳密な実行順序に依存する RCSI でワークロードを同時実行しているお客様に対する一般的な推奨事項は、より厳格な分離レベル (たとえば REPEATABLE READSERIALIZABLE) を使用することです。

最適化されたロックの診断に関する追加機能

次の改善点は、最適化されたロックが有効になっている場合の、ブロックとデッドロック状態の監視とトラブルシューティングに役立ちます。

  • 最適化されたロックの待機の種類
    • XACT TIDに対するSロック待機タイプと、sys.dm_os_wait_stats内のリソース説明:
      • LCK_M_S_XACT_READ - タスクが、読み取りを目的としている XACTwait_resource 型の共有ロックを待機中の場合に発生します。
      • LCK_M_S_XACT_MODIFY - タスクが、変更を目的としている XACTwait_resource 型の共有ロックを待機中の場合に発生します。
      • LCK_M_S_XACT - タスクが、目的を推測できない XACTwait_resource 型の共有ロックを待機しているときに発生します。 このシナリオは一般的ではありません。
  • ロック リソースの可視性
  • リソースの可視性を待機する
  • デッドロック グラフ
    • デッドロック状態レポート <resource-list> の各リソースにおいて、各 <xactlock> 要素は、基になるリソースとデッドロック状態の各メンバーのロックに関する特定の情報を報告します。 詳細と例については、「最適化されたロックとデッドロック」を参照してください。
  • 拡張イベント
    • lock_after_qual_stmt_abort イベントは、別のトランザクションとの競合が原因でステートメントが内部的に再処理されたときに発生します。 詳細については、「修飾後のロック (LAQ)」を参照してください。
    • locking_stats イベントは、数分ごとにデータベースごとに発生し、ロックエスカレーションの数、最適化されたロックの TID ロックと LAQ コンポーネントが有効かどうか、LAQ がさまざまな理由で使用されなかったクエリの数など、時間間隔の集計ロック統計を提供します。 このイベントは、最適化されたロックが無効になっている場合でも発生します。
    • SQL Server と Azure SQL Managed Instance では、 locking_stats2 イベントは数分ごとにデータベースごとに発生し、時間間隔の インデックス ロックLAQ ヒューリスティック 統計をスキップします。

最適化されたロックを使用したベスト プラクティス

読み取りコミット済み スナップショット分離 (RCSI) を有効にする

最適化されたロックの利点を最大限に活用するには、データベースで 読み取りコミット済みスナップショット分離 (RCSI) を有効にし、既定の分離レベルとして READ COMMITTED 分離を使用することをお勧めします。

Microsoft Fabric の Azure SQL Database と SQL Database では、RCSI は既定で有効になっており、 READ COMMITTED は既定の分離レベルです。 RCSI が有効で、READ COMMITTED 分離レベルを使用している場合、閲覧者はステートメントの開始時に取得されたスナップショットから行のバージョンを読み取ります。 LAQ を使用すると、ライターは U ロックを取得せずに、行の最新のコミット済みバージョンに基づいて述語ごとに行を修飾します。 LAQ では、クエリは行が条件を満たし、その行にアクティブな書き込みトランザクションがある場合にのみ待機します。 最新のコミット済みバージョンに基づいて修飾し、修飾された行のみをロックすると、ブロックが減り、同時実行性が向上します。

ヒントのロック化を回避する

テーブル ヒントやクエリ ヒント (たとえば、UPDLOCKREADCOMMITTEDLOCKXLOCKHOLDLOCK など) は、最適化ロックが有効な場合でも有効ですが、最適化ロックのメリットが損なわれます。 ロック ヒントは、ロック ヒントの意図を尊重するために、行またはページのロックを取得し、トランザクションの終了までそれらを保持することをデータベース エンジンに強制します。 一部のアプリケーションには、ロック ヒントが必要なロジックがあります。たとえば、UPDLOCK ヒントで行を読み取り、後で更新する場合です。 ロック ヒントは、必要な場合にのみ使用することをおすすめします。

最適化されたロックを使用する場合、既存のクエリに制限はなく、クエリを書き直す必要もありません。 ヒントを使用していないクエリは、最適化されたロックから最も大きな利益を得ます。

クエリ内の 1 つのテーブルに対するテーブル ヒントによって、同じクエリ内の他のテーブルに対する最適化されたロックが無効になることはありません。 さらに、最適化されたロックは、INSERTUPDATEDELETEMERGE などのDML ステートメントによって更新されるテーブルのロック ビヘイビアーにのみ影響します。 例えば次が挙げられます。

CREATE TABLE t5
(
a int NOT NULL,
b int NOT NULL
);

CREATE TABLE t6
(
a int NOT NULL,
b int NOT NULL
);
GO

INSERT INTO t5 VALUES (1,10),(2,20),(3,30);
INSERT INTO t6 VALUES (1,10),(2,20),(3,30);
GO

UPDATE t5 SET t5.b = t6.b
FROM t5
INNER JOIN t6 WITH (UPDLOCK)
ON t5.a = t6.a;

前のクエリの例では、テーブル t6 のみがロック ヒントの影響を受けますが、t5 は最適化されたロックの利点を引き続き利用できます。

UPDATE t5
    SET t5.b = t6.b
FROM t5 WITH (REPEATABLEREAD)
     INNER JOIN t6
         ON t5.a = t6.a;

前のクエリの例では、t5 分離レベルを使用し、トランザクションが終了するまでロックを保持するのはテーブル REPEATABLE READ だけです。 その他は、t5 が最適化されたロックの恩恵を受けるよう更新します。 HOLDLOCK ヒントにも同じことが当てはまります。

よく寄せられる質問 (FAQ)

新規データベースと既存データベースの両方で、最適化されたロックは既定でオンになっていますか?

Azure SQL Database、Azure SQL Managed InstanceAUTD、および Microsoft Fabric の SQL データベースでは、はい。 SQL Server 2025 (17.x) では、最適化されたロックは既定で無効になっていますが、高速データベース復旧が有効になっているすべてのユーザー データベースで有効にすることができます。

最適化されたロックが有効になっているかどうかを検出するにはどうすればよいですか?

「最適化されたロックが有効になっているか」を参照してください。

最適化されたロックにもかかわらずクエリを強制的にブロックする場合はどうすればよいでしょうか?

RCSI が有効になっている場合は、 READCOMMITTEDLOCK テーブル ヒントを使用して、最適化されたロックが有効になっているときに 2 つのクエリ間でブロックを強制します。

最適化されたロックは読み取り専用セカンダリ レプリカで使用されますか?

いいえ。読み取り専用レプリカ上では DML ステートメントを実行できず、対応する行およびページのロックは取得されないからです。

tempdb および一時テーブルのデータを変更するときに、最適化されたロックは使用されますか?

現時点ではできません。