テーブル ヒント (Transact-SQL)

適用対象:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

テーブル ヒントは、データ操作言語 (DML) ステートメントの実行中、クエリ オプティマイザーの既定の動作をオーバーライドするために使用されます。 ロック方法、1 つ以上のインデックス、クエリ処理操作 (テーブル スキャンやインデックス シークなど)、その他のオプションを指定できます。 テーブル ヒントは、DML ステートメントの FROM 句で指定され、その句で参照されるテーブルまたはビューのみに影響します。

注意事項

通常、SQL Server クエリ オプティマイザーでは、クエリにとって最適な実行プランが選択されるため、ヒントは、経験を積んだ開発者やデータベース管理者が最後の手段としてのみ使用することをお勧めします。

適用対象:

Transact-SQL 構文表記規則

構文

WITH  ( <table_hint> [ [ , ] ...n ] )

<table_hint> ::=
{ NOEXPAND
  | INDEX ( <index_value> [ , ...n ] ) | INDEX = ( <index_value> )
  | FORCESEEK [ ( <index_value> ( <index_column_name> [ , ... ] ) ) ]
  | FORCESCAN
  | HOLDLOCK
  | NOLOCK
  | NOWAIT
  | PAGLOCK
  | READCOMMITTED
  | READCOMMITTEDLOCK
  | READPAST
  | READUNCOMMITTED
  | REPEATABLEREAD
  | ROWLOCK
  | SERIALIZABLE
  | SNAPSHOT
  | SPATIAL_WINDOW_MAX_CELLS = <integer_value>
  | TABLOCK
  | TABLOCKX
  | UPDLOCK
  | XLOCK
}

<table_hint_limited> ::=
{
    KEEPIDENTITY
  | KEEPDEFAULTS
  | HOLDLOCK
  | IGNORE_CONSTRAINTS
  | IGNORE_TRIGGERS
  | NOLOCK
  | NOWAIT
  | PAGLOCK
  | READCOMMITTED
  | READCOMMITTEDLOCK
  | READPAST
  | REPEATABLEREAD
  | ROWLOCK
  | SERIALIZABLE
  | SNAPSHOT
  | TABLOCK
  | TABLOCKX
  | UPDLOCK
  | XLOCK
}

Note

SQL Server 2014 (12.x) 以前のバージョンの Transact-SQL 構文を確認するには、以前のバージョンのドキュメントを参照してください。

引数

WITH ( <table_hint> ) [ [ , ] ...n ]

いくつかの例外を除き、テーブル ヒントは、FROM 句で WITH キーワードを使用して指定した場合にのみサポートされます。 また、テーブル ヒントはかっこを使用して指定する必要があります。

重要

WITH キーワード (keyword)の省略は非推奨の機能です。この機能は、今後のバージョンの SQL Server で削除される予定です。 新規の開発作業ではこの機能を使用しないようにし、現在この機能を使用しているアプリケーションは修正することを検討してください。

次のテーブル ヒントは、WITH キーワードの有無にかかわらず許可されます: NOLOCKREADUNCOMMITTEDUPDLOCKREPEATABLEREADSERIALIZABLEREADCOMMITTEDTABLOCKTABLOCKXPAGLOCKROWLOCKNOWAITREADPASTXLOCKSNAPSHOT、および NOEXPANDWITH キーワードを使用せずにこれらのテーブル ヒントを指定する場合、ヒントは単独で指定する必要があります。 次に例を示します。

FROM t (TABLOCK)

ヒントを他のオプションと一緒に指定する場合は、次のように WITH キーワードを使用して指定する必要があります。

FROM t WITH (TABLOCK, INDEX(myindex))

複数のテーブル ヒント間にはコンマを使用することをお勧めします。

重要

コンマではなくスペースでヒントを区切ることは非推奨の機能です。この機能は、今後のバージョンの SQL Server で削除される予定です。 新規の開発作業ではこの機能を使用しないようにし、現在この機能を使用しているアプリケーションは修正することを検討してください。

NOEXPAND

クエリ オプティマイザーがクエリを処理するときに、基になるテーブルにアクセスするためにインデックス付きビューを展開しないことを指定します。 クエリ オプティマイザーは、ビューをクラスター化インデックスを持つテーブルのように取り扱います。 NOEXPAND は、インデックス付きビューにのみ適用されます。 詳細については、「NOEXPAND の使用」を参照してください。

INDEX ( <index_value> [ , ...n ] ) | INDEX = ( <index_value> )

INDEX() 構文では、ステートメントを処理するときにクエリ オプティマイザーによって使用される 1 つ以上のインデックスの名前または ID を指定します。 一方、INDEX = 構文では、単一のインデックス値を指定します。 各テーブルに対して指定できるのは 1 つのインデックス ヒントだけです。

クラスター化インデックスがある場合、INDEX(0) はクラスター化インデックスのスキャンを強制し、INDEX(1) はクラスター化インデックスのスキャンまたはシークを強制します。 クラスター化インデックスがない場合、INDEX(0) はテーブル スキャンを強制し、INDEX(1) はエラーと見なされます。

1 つのヒント リストの中で複数のインデックスが使用されている場合、重複するものは無視され、一覧表示されている残りのインデックスを使用してテーブルの行が取得されます。 インデックス ヒント内のインデックスの順番は重要です。 複数のインデックス ヒントはインデックスの AND 処理も設定し、クエリ オプティマイザーはアクセスされる各インデックスに可能な限り多くの条件を適用します。 ヒント インデックスのコレクションに、クエリで参照される列のすべてが含まれていない場合、SQL Server データベース エンジンによってすべてのインデックス付き列が取得された後、フェッチを実行して残りの列が取得されます。

Note

複数のインデックスを参照するインデックス ヒントが、スター結合のファクト テーブルで使用されている場合、オプティマイザーはそのインデックス ヒントを無視し、警告メッセージを返します。 また、インデックス論理和は、インデックス ヒントが指定されたテーブルでは許可されません。

テーブル ヒント内のインデックスの最大個数は、非クラスター化インデックスが 250 個です。

KEEPIDENTITY

OPENROWSET で BULK オプションを使用する場合にのみ、INSERT ステートメントで適用できます。

インポートしたデータ ファイルの ID 値 (複数可) を ID 列に使用することを指定します。 KEEPIDENTITY を指定しない場合、この列の ID 値は確認されるのみでインポートされません。クエリ オプティマイザーでは、テーブルの作成時に指定されたシードおよび増分の値を基に一意な値を自動的に割り当てられます。

重要

テーブルやビューの ID 列の値がデータ ファイルに含まれておらず、ID 列がテーブルの最終列でもない場合は、その ID 列をスキップする必要があります。 詳細については、「フォーマット ファイルを使用したデータ フィールドのスキップ (SQL Server)」を参照してください。 ID 列のスキップに成功すると、クエリ オプティマイザーは、その ID 列の一意な値を、インポートされたテーブル行に自動的に割り当てます。

このヒントを INSERT ... SELECT * FROM OPENROWSET(BULK...) ステートメントに使用する例については、「データの一括インポート時の ID 値の保持 (SQL Server)」を参照してください。

テーブルの ID 値の確認については、「DBCC CHECKIDENT (Transact-SQL)」を参照してください。

KEEPDEFAULTS

OPENROWSET で BULK オプションを使用する場合にのみ、INSERT ステートメントで適用できます。

データ レコードにテーブルの列値が含まれていない場合に、NULL の代わりにテーブル列の既定値を挿入することを指定します。

このヒントを INSERT ...SELECT * FROM OPENROWSET(BULK...) ステートメントに使用する例については、「一括インポート中の NULL の保持または既定値の使用 (SQL Server)」を参照してください。

FORCESEEK [ ( <index_value> ( <index_column_name> [ , ...n ] ) ) ]

クエリ オプティマイザーで、テーブルまたはビュー内のデータへのアクセス パスとしてインデックス シーク操作のみを使用するように指定します。

注意

SQL Server 2008 R2 (10.50.x) Service Pack 1 以降では、インデックス パラメーターも指定できます。 その場合、一度でも指定されたインデックス列が使用されると、クエリ オプティマイザーでは指定されたインデックスを介したインデックスのシーク操作のみが検討されます。

  • index_value

    インデックス名またはインデックス ID 値。 インデックス ID 0 (ヒープ) は指定できません。 インデックスの名前または ID を返すには、sys.indexes カタログ ビューにクエリを実行します。

  • index_column_name

    シーク操作に含めるインデックス列の名前。 インデックス パラメーターと共に FORCESEEK を指定することは、INDEX ヒントと共に FORCESEEK を使用することと同じです。 ただし、シーク対象のインデックスとシーク操作で考慮するインデックス列の両方を指定することで、クエリ オプティマイザーで使用されるアクセス パスをより詳細に制御できるようになります。 オプティマイザーでは、必要に応じて、追加の列が検討される場合もあります。 たとえば、非クラスター化インデックスが指定されている場合、オプティマイザーでは、指定された列に加え、クラスター化インデックスのキー列を使用することもできます。

FORCESEEK は以下の方法で指定できます。

構文 説明
インデックスまたは INDEX ヒントを使用しない場合 FROM dbo.MyTable WITH (FORCESEEK) クエリ オプティマイザーでは、関連するインデックスを介してテーブルやビューにアクセスするためのインデックスのシーク操作のみが検討されます。
INDEX ヒントと組み合わせた場合 FROM dbo.MyTable WITH (FORCESEEK, INDEX (MyIndex)) クエリ オプティマイザーでは、指定されたインデックスを介してテーブルやビューにアクセスするためのインデックスのシーク操作のみが検討されます。
インデックスとインデックス列を指定してパラメーター化する場合 FROM dbo.MyTable WITH (FORCESEEK (MyIndex (col1, col2, col3))) 少なくとも指定されたインデックス列を使用した場合、クエリ オプティマイザーでは、指定されたインデックスを介してテーブルやビューにアクセスするためのインデックスのシーク操作のみが検討されます。

(インデックス パラメーターを使用するかどうかにかかわらず) FORCESEEK ヒントを使用する際は、次のガイドラインを考慮してください。

  • ヒントは、テーブル ヒントまたはクエリ ヒントとして指定できます。 クエリ ヒントの詳細については、「クエリ ヒント (Transact-SQL)」を参照してください。
  • インデックス付きビューに FORCESEEK を適用するには、NOEXPAND ヒントも指定する必要があります。
  • ヒントは、テーブルまたはビューごとに 1 回だけ適用できます。
  • このヒントは、リモート データ ソースには指定できません。 インデックス ヒントと共に FORCESEEK を指定すると、エラー 7377 が返されます。また、インデックス ヒントなしで FORCESEEK を使用すると、エラー 8180 が返されます。
  • FORCESEEK が原因でプランが見つからない場合、エラー 8622 が返されます。

インデックス パラメーターと共に FORCESEEK を指定する場合、次のガイドラインと制限が適用されます。

  • このヒントは、INSERT、UPDATE、または DELETE ステートメントの対象であるテーブルには指定できません。
  • このヒントを INDEX ヒントまたは別の FORCESEEK ヒントと組み合わせて指定することはできません。
  • 少なくとも 1 列を指定する必要があり、先頭のキー列にする必要があります。
  • 追加のインデックス列を指定できますが、キー列を省略することはできません。 たとえば、指定されたインデックスに ab、および c というキー列が含まれている場合、有効な構文には FORCESEEK (MyIndex (a)) および FORCESEEK (MyIndex (a, b) が含まれます。 無効な構文には、FORCESEEK (MyIndex (c))FORCESEEK (MyIndex (a, c) が含まれます。
  • ヒントで指定された列名の順序は、参照先のインデックスでの列の順序と一致させる必要があります。
  • インデックス キーの定義にない列を指定することはできません。 たとえば、非クラスター化インデックスでは、定義されたインデックス キー列のみを指定できます。 インデックスに自動的に含まれるクラスター化キー列を指定することはできませんが、オプティマイザーでは使用できます。
  • xVelocity メモリ最適化列ストア インデックスをインデックス パラメーターとして指定することはできません。 エラー 366 が返されます。
  • インデックス定義を変更すると (列の追加や削除など)、そのインデックスを参照するクエリに対する変更も必要になる場合があります。
  • ヒントを使用すると、オプティマイザーでは、テーブル上の空間インデックスまたは XML インデックスが検討されなくなります。
  • このヒントを FORCESCAN ヒントと組み合わせて指定することはできません。
  • パーティション インデックスの場合、SQL Server によって暗黙的に追加されたパーティション分割列を FORCESEEK ヒントで指定することはできません。

注意事項

パラメーターと共に FORCESEEK を指定すると、オプティマイザーが考慮することができるプランの数が、パラメーターなしで FORCESEEK を指定した場合よりも制限されます。 これにより、Plan cannot be generated というエラーが生じる回数が増加する可能性があります。 将来のリリースでは、クエリ オプティマイザーに対して内部変更を行うため、より多くのプランを考慮できるようになります。

FORCESCAN

適用対象: SQL Server 2008 R2 (10.50.x) Service Pack 1 以降のバージョン

クエリ オプティマイザーで、テーブルまたはビュー内のデータへのアクセス パスとしてインデックス シーク操作のみを使用するように指定します。 FORCESCAN ヒントは、オプティマイザーが影響を受ける行数を過小評価し、スキャン操作ではなくシーク操作を選択するクエリに役立ちます。 この場合、操作に許可されるメモリの量が少なすぎて、クエリのパフォーマンスに影響します。

FORCESCAN を指定する際には、INDEX ヒントを使用してもしなくてもかまいません。 インデックス ヒント (INDEX = index_name, FORCESCAN) と組み合わせると、クエリ オプティマイザーでは、参照されるテーブルにアクセスする際に、指定されたインデックスを介したスキャン アクセス パスのみが考慮されます。 FORCESCANをインデックス ヒント INDEX(0) 共に指定すると、ベース テーブルに対するテーブル スキャン操作を強制できます。

パーティション テーブルおよびパーティション インデックスの場合、FORCESCAN は、クエリの述語評価によってパーティションが削除された後に適用されます。 つまり、スキャンは、テーブル全体ではなく、残りのパーティションのみに適用されます。

FORCESCAN ヒントには、次の制限があります。

  • このヒントは、INSERT、UPDATE、または DELETE ステートメントの対象であるテーブルには指定できません。
  • このヒントを複数のインデックス ヒントと共に使用することはできません。
  • このヒントを使用すると、クエリ オプティマイザーで、テーブル上の空間インデックスまたは XML インデックスが考慮されなくなります。
  • このヒントは、リモート データ ソースには指定できません。
  • このヒントを FORCESEEK ヒントと組み合わせて指定することはできません。

HOLDLOCK

これは、SERIALIZABLE に相当します。 詳細については、後の「SERIALIZABLE」を参照してください。 HOLDLOCK は、指定されたテーブルまたはビューに対してのみ、かつ使用されているステートメントによって定義されたトランザクションが実行されている間にのみ適用されます。 HOLDLOCK は、FOR BROWSE オプションを含む SELECT ステートメントでは使用できません。

IGNORE_CONSTRAINTS

OPENROWSET で BULK オプションを使用する場合にのみ、INSERT ステートメントで適用できます。

テーブルに対する制約を一括インポート操作時に無視することを指定します。 既定では、INSERT は Unique 制約と CHECK 制約および主キー制約と外部キー制約をチェックします。 一括インポート操作の際に IGNORE_CONSTRAINTS を指定している場合、インポート対象のテーブルに対する制約が無視されます。 UNIQUE、PRIMARY KEY、または NOT NULL の各制約を無効にすることはできません。

制約に違反する行が入力データに含まれている場合に、CHECK 制約および FOREIGN KEY 制約を無効化することができます。 CHECK 制約および FOREIGN KEY 制約を無効化することによって、データをインポートしてから、Transact-SQL ステートメントを使用してデータをクリーンアップできます。

ただし、CHECK 制約および FOREIGN KEY 制約を無視すると、操作の後、テーブルに設定されている制約のうち、無視された制約は sys.check_constraints カタログ ビューまたは sys.foreign_keys カタログ ビューで is_not_trusted とマークされます。 テーブル全体の制約は、任意の時点で必ず検証してください。 一括インポート操作の前にテーブルが空白になっていない場合、制約を再検証するコストは、CHECK および FOREIGN KEY 制約を増分データに適用するコストを上回る可能性があります。

IGNORE_TRIGGERS

OPENROWSET で BULK オプションを使用する場合にのみ、INSERT ステートメントで適用できます。

テーブルに対して定義されたトリガーを、一括インポート操作時に無視することを指定します。 既定では、INSERT はトリガーを適用します。

IGNORE_TRIGGERS は、アプリケーションがトリガーに依存せず、パフォーマンスの最大化が重要な場合にのみ使用してください。

NOLOCK

これは、READUNCOMMITTED に相当します。 詳細については、後の「READUNCOMMITTED」を参照してください。

Note

UPDATE ステートメントまたは DELETE ステートメントの場合: この機能は、今後のバージョンの SQL Server で削除される予定です。 新規の開発作業ではこの機能を使用しないようにし、現在この機能を使用しているアプリケーションは修正することを検討してください。

NOWAIT

テーブルでロックがかかったらすぐにメッセージを返すようにデータベース エンジンを設定します。 NOWAIT は、特定のテーブルに SET LOCK_TIMEOUT 0 を指定することと同じです。 TABLOCK ヒントも含まれている場合、NOWAIT ヒントは機能しません。 TABLOCK ヒントを使用している場合に待機しないでクエリを終了するには、代わりにクエリの前に SET LOCK_TIMEOUT 0; を指定します。

PAGLOCK

通常使用される行やキーに対する個々のロックまたは単一のテーブル ロックの代わりに、ページ ロックを使用します。 既定では、操作に適したロック モードを使用します。 SNAPSHOT 分離レベルで動作するトランザクションで PAGLOCK を指定する場合、ロックを必要とする他のテーブル ヒント (UPDLOCKHOLDLOCK など) と組み合わせて指定しない限り、ページ ロックは取得されません。

READCOMMITTED

読み取り操作が、ロックまたは行のバージョン管理を使用して、READ COMMITTED 分離レベルのルールに従うことを指定します。 データベース オプション READ_COMMITTED_SNAPSHOT が OFF の場合、データベース エンジンでは、データの読み取り時に共有ロックを獲得し、読み取り操作が完了するとそれらのロックを解放します。 データベース オプション READ_COMMITTED_SNAPSHOT が ON の場合、データベース エンジンでは、ロックを獲得せず、行のバージョン管理を使用します。 分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。

Note

UPDATE ステートメントまたは DELETE ステートメントの場合: この機能は、今後のバージョンの SQL Server で削除される予定です。 新規の開発作業ではこの機能を使用しないようにし、現在この機能を使用しているアプリケーションは修正することを検討してください。

READCOMMITTEDLOCK

読み取り操作が、ロックを使用して、READ COMMITTED 分離レベルのルールに従うことを指定します。 READ_COMMITTED_SNAPSHOT データベース オプションの設定にかかわらず、データベース エンジンでは、データの読み取り時に共有ロックを獲得し、読み取り操作が完了するとそれらのロックを解放します。 分離の詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。 このヒントは、INSERT ステートメントのターゲット テーブルには指定できません。指定すると、エラー 4140 が返されます。

READPAST

他のトランザクションによってロックされている行を、データベース エンジンで読み取らないことを指定します。 READPAST を指定すると、行レベルのロックはスキップされますが、ページレベルのロックはスキップされません。 つまり、データベース エンジンは、ロックが解除されるまで現在のトランザクションをブロックする代わりに、行をスキップします。 たとえば、テーブル T1 に整数型の列が 1 つあり、値 1、2、3、4、5 が格納されているとします。 トランザクション A で値 3 を 8 に変更し、この変更をまだコミットしていない場合、SELECT * FROM T1 (READPAST) によって値 1、2、4、5 が生成されます。 READPAST は主に、SQL Server テーブルを使用する作業キューの実装時に、ロックの競合を減らすために使用されます。 READPAST を使用するキュー リーダーは、他のトランザクションによってロックされた過去のキュー エントリを次に使用可能なキュー エントリにスキップします。他のトランザクションがロックを解放するまで待つ必要はありません。

READPAST は、UPDATE または DELETE ステートメントで参照されるテーブル、および FROM 句で参照されるテーブルに対して指定できます。 UPDATE ステートメントで指定された場合、READPAST は、ステートメントのどこで指定されているかに関係なく、更新するレコードを識別するためにデータを読み取るときにのみ適用されます。 INSERT ステートメントの INTO 句でテーブルに対して READPAST を指定することはできません。 更新または削除操作で READPAST を使用すると、外部キーまたはインデックス付きビューの読み取り時、またはセカンダリ インデックスの変更時にブロックが発生する場合があります。

READPAST は、READ COMMITTED または REPEATABLE READ 分離レベルで動作するトランザクションでのみ指定できます。 SNAPSHOT 分離レベルで動作するトランザクションで READPAST を指定する場合、ロックを必要とする他のテーブル ヒント (UPDLOCKHOLDLOCK など) と組み合わせて指定する必要があります。

READ_COMMITTED_SNAPSHOT データベース オプションが ON に設定され、次の条件のいずれかに該当する場合、READPAST テーブル ヒントを指定することはできません。

  • セッションのトランザクション分離レベルが READ COMMITTED の場合
  • クエリで READCOMMITTED テーブル ヒントも指定されている。

このような場合に READPAST ヒントを指定するには、READCOMMITTED テーブル ヒントがあればそれを削除し、クエリに READCOMMITTEDLOCK テーブル ヒントを含めます。

READUNCOMMITTED

ダーティ リードを許可することを指定します。 現在のトランザクションによって読み取られたデータが、他のトランザクションによって変更されるのを防ぐために、共有ロックは発行されません。また、他のトランザクションによって排他ロックが設定されていても、ロックされたデータを現在のトランザクションで読み取ることはブロックされません。 ダーティ リードを許可するとコンカレンシーが高まりますが、他のトランザクションによってロールバックされているデータ変更を読み取る可能性があります。 この結果、トランザクションでエラーが発生したり、コミットされていないデータがユーザーに提示されたり、レコードが重複表示されたりまったく表示されなかったりする場合があります。

READUNCOMMITTED および NOLOCK ヒントは、データのロックにのみ適用されます。 READUNCOMMITTED および NOLOCK ヒントを含むクエリを含め、すべてのクエリは、コンパイルおよび実行時に Sch-S (スキーマ安定度) ロックを獲得します。 このため、同時実行トランザクションがテーブルの Sch-M (スキーマ修正) ロックを保持している場合、クエリはブロックされます。 たとえば、データ定義言語 (DDL) 操作では、テーブルのスキーマ情報を変更する前にスキーマ修正 (Sch-M) ロックを取得します。 READUNCOMMITTED または NOLOCK を指定して実行されるクエリを含め、すべての同時クエリは、Sch-S ロックを獲得しようとするとブロックされます。 一方、スキーマ安定度 (Sch-S) ロックを保持するクエリによって、スキーマ修正 (Sch-M) ロックを取得しようとする同時実行トランザクションはブロックされます。

挿入、更新、または削除の操作によって変更されたテーブルに対して、READUNCOMMITTED および NOLOCK を指定することはできません。 SQL Server クエリ オプティマイザーでは、UPDATE または DELETE ステートメントのターゲット テーブルに適用される FROM 句内の READUNCOMMITTED および NOLOCK ヒントは無視されます。

注意

SQL Server の将来のバージョンでは、UPDATE または DELETE ステートメントのターゲット テーブルに適用される FROM 句での READUNCOMMITTED および NOLOCK ヒントの使用はサポートされなくなる予定です。 新しい開発作業ではこのコンテキストでのヒントの使用を避け、現在このヒントを使用しているアプリケーションは変更を検討してください。

次のいずれかを使用することによって、ロックの競合を最小限に抑えながら、コミットされていないデータ変更のダーティ リードからトランザクションを保護することができます。

  • READ COMMITTED 分離レベル (READ_COMMITTED_SNAPSHOT データベース オプションを ON に設定)。
  • SNAPSHOT 分離レベル。

分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。

Note

READUNCOMMITTED を指定しているときに エラー メッセージ 601 が表示された場合は、デッドロック エラー (エラー メッセージ 1205) の場合と同様に解決し、ステートメントを再試行してください。

REPEATABLEREAD

REPEATABLE READ 分離レベルで実行しているトランザクションと同じロック セマンティクスでスキャンを実行することを指定します。 分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。

ROWLOCK

通常取得されるページ ロックまたはテーブル ロックの代わりに、行ロックを取得することを指定します。 SNAPSHOT 分離レベルで動作するトランザクションで ROWLOCK を指定する場合、ロックを必要とする他のテーブル ヒント (UPDLOCKHOLDLOCK など) と組み合わせて指定しない限り、行ロックは取得されません。 クラスター化された列ストア インデックスのあるテーブルでは、ROWLOCK を使用することはできません。 次の例では、アプリケーションにエラー 651 が返されます。

UPDATE [dbo].[FactResellerSalesXL_CCI] WITH (ROWLOCK)
SET UnitPrice = 50
WHERE ProductKey = 150;

SERIALIZABLE

これは、HOLDLOCK に相当します。 共有ロックがより制限的になります。テーブルまたはデータ ページが不要になったときに、トランザクションが完了しているかどうかにかかわらず共有ロックが解除されるのではなく、共有ロックはトランザクションが完了するまで保持されます。 スキャンは、SERIALIZABLE 分離レベルで実行されるトランザクションと同じセマンティクスで実行されます。 分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。

SNAPSHOT

適用対象: SQL Server 2014 (12.x) 以降のバージョン

メモリ最適化されたテーブルは、SNAPSHOT 分離でアクセスされます。 次の例で示すように、SNAPSHOT は、メモリ最適化テーブルのみで使用できます (ディスク ベースのテーブルでは使用できません)。 詳細については、「メモリ最適化テーブルの概要」を参照してください。

SELECT *
FROM dbo.Customers AS c WITH (SNAPSHOT)
LEFT JOIN dbo.[Order History] AS oh
    ON c.customer_id=oh.customer_id;

SPATIAL_WINDOW_MAX_CELLS = <integer_value>

適用対象: SQL Server 2012 (11.x) 以降のバージョン

geometry オブジェクトや geography オブジェクトのテセレーションに使用するセルの最大数を指定します。 <integer_value> は、1 - 8192 の整数値です。

このオプションを使用すると、プライマリとセカンダリのフィルターの実行時間の間のトレードオフを調整することによって、クエリの実行時間を微調整できます。 値を大きくすると、セカンダリ フィルターの実行時間が短縮されますが、プライマリ フィルターの実行時間が増加します。値を小さくすると、プライマリ フィルターの実行時間が短縮されますが、セカンダリ フィルターの実行時間が増加します。 密度の高い空間データの場合は、大きい値を指定して、プライマリ フィルターでより適切な近似値を提供し、セカンダリ フィルターの実行時間を減少させることで、実行時間を短縮させます。 密度の低いデータの場合は、小さい値を指定して、プライマリ フィルターの実行時間を短縮します。

このオプションは、手動と自動の両方のグリッド テセレーションに使用できます。

TABLOCK

取得したロックがテーブル レベルで適用されることを指定します。 取得されるロックの種類は、実行されるステートメントによって異なります。 たとえば、SELECT ステートメントを実行すると、共有ロックが取得されます。 TABLOCK を指定することで、共有ロックが、行またはページ レベルではなくテーブル全体に適用されます。 HOLDLOCK も指定されている場合、テーブル ロックはトランザクションが終了するまで保持されます。

INSERT INTO <target_table> SELECT <columns> FROM <source_table> ステートメントを使用してデータをヒープにインポートする場合、ターゲット テーブルに対して TABLOCK ヒントを指定すると、そのステートメントに対して最小限のログと最適なロックを有効にすることができます。 データベース復旧モデルが単純復旧モデルまたは一括ログ復旧モデルに設定されている必要もあります。 TABLOCK ヒントを使用すると、ヒープまたはクラスター化列ストア インデックスに対する並列挿入も有効になります。 詳細については、「INSERT (Transact-SQL)」を参照してください。

テーブルにデータをインポートするため、OPENROWSET 一括行セット プロバイダーで TABLOCK を使用すると、ログとロックを最適化して、ターゲット テーブルへのデータの読み込みを複数のクライアントで同時に行うことができます。 詳細については、「一括インポートで最小ログ記録を行うための前提条件」次を参照してください。

TABLOCKX

テーブルに排他ロックを使用することを指定します。

UPDLOCK

更新ロックを使用することと、これをトランザクション終了まで保持することを指定します。 UPDLOCK を使用すると、行レベルまたはページ レベルの読み取り操作に対してのみ更新ロックが適用されます。 UPDLOCKTABLOCK と組み合わせるか、なんらかの理由でテーブル レベルのロックを取得すると、代わりに排他 (X) ロックが取得されます。

UPDLOCK を指定すると、READCOMMITTED および READCOMMITTEDLOCK 分離レベルのヒントは無視されます。 たとえば、セッションの分離レベルを SERIALIZABLE に設定し、クエリで (UPDLOCKREADCOMMITTED) を指定すると、READCOMMITTED ヒントは無視され、トランザクションは SERIALIZABLE 分離レベルを使用して実行されます。

XLOCK

排他ロックを使用することと、これをトランザクション終了まで保持することを指定します。 ROWLOCKPAGLOCK、または TABLOCK と組み合わせて指定すると、排他ロックは適切な粒度レベルに適用されます。

注釈

テーブルがクエリ プランによってアクセスされない場合、テーブル ヒントは無視されます。 これは、オプティマイザーがテーブルにまったくアクセスしないことを選択した結果であるか、またはインデックス付きビューが代わりにアクセスされるためである可能性があります。 後者の場合、OPTION (EXPAND VIEWS) クエリ ヒントを使用することで、インデックス付きビューへのアクセスを防ぐことができます。

すべてのロック ヒントが、クエリ プランによってアクセスされているすべてのテーブルおよびビュー (ビューで参照されているテーブルおよびビューを含む) に反映されます。 また、SQL Server は、対応するロックの整合性チェックを実行します。

行レベルのロックを獲得するロック ヒント ROWLOCKUPDLOCKXLOCK では、実際のデータ行ではなくインデックス キーに対してロックが実行される場合があります。 たとえば、テーブルに非クラスター化インデックスがあり、ロック ヒントを使用する SELECT ステートメントがカバーするインデックスによって処理される場合、ベース テーブルのデータ行ではなく、カバーするインデックスのインデックス キーに対してロックが取得されます。

テーブルに計算列が含まれており、その計算列が、別のテーブル内の列にアクセスする式または関数によって計算される場合、テーブル ヒントがそれらのテーブルで使用されたり、反映されたりすることはありません。 たとえば、クエリ内のテーブルに NOLOCK テーブル ヒントが指定されているものとします。 このテーブルには、別のテーブル内の列にアクセスする式と関数の組み合わせで計算される、計算列があります。 式と関数で参照されるテーブルでは、アクセスされるときに NOLOCK テーブル ヒントが使用されることはありません。

SQL Server では、FROM 句内の各テーブルに対して、次の各グループの複数のテーブル ヒントを使用することはできません。

  • 粒度ヒント: PAGLOCKNOLOCKREADCOMMITTEDLOCKROWLOCKTABLOCKTABLOCKX
  • 分離レベル ヒント: HOLDLOCKNOLOCKREADCOMMITTEDREPEATABLEREADSERIALIZABLE

フィルター選択されたインデックス ヒント

フィルター選択されたインデックスをテーブル ヒントとして使用できますが、クエリで選択される行がすべて対象ではない場合、クエリ オプティマイザーによってエラー 8622 が生成されます。 フィルター選択されたインデックス ヒントが無効になる例を次に示します。 この例では、フィルター選択されたインデックス FIBillOfMaterialsWithComponentID を作成し、SELECT ステートメントのインデックス ヒントとして使用します。 フィルター選択されたインデックスの述語には、ComponentID が 533、324、および 753 のデータ行が含まれています。 クエリ述語にも ComponentID が 533、324、753 のデータ行が含まれていますが、ComponentID 855 および 924 も含めるように結果セットが拡張されています。これらは、フィルター選択されたインデックスには含まれていません。 したがって、クエリ オプティマイザーは、フィルター選択されたインデックス ヒントを使用できず、エラー 8622 が生成されます。 詳細については、「 Create Filtered Indexes」を参照してください。

IF EXISTS (SELECT name FROM sys.indexes
    WHERE name = N'FIBillOfMaterialsWithComponentID'
    AND object_id = OBJECT_ID(N'Production.BillOfMaterials'))
DROP INDEX FIBillOfMaterialsWithComponentID
    ON Production.BillOfMaterials;
GO
CREATE NONCLUSTERED INDEX "FIBillOfMaterialsWithComponentID"
    ON Production.BillOfMaterials (ComponentID, StartDate, EndDate)
    WHERE ComponentID IN (533, 324, 753);
GO
SELECT StartDate, ComponentID FROM Production.BillOfMaterials
    WITH(INDEX (FIBillOfMaterialsWithComponentID))
    WHERE ComponentID in (533, 324, 753, 855, 924);
GO

SET オプションに、フィルター選択されたインデックスに必要な値がない場合、クエリ オプティマイザーではインデックス ヒントが考慮されません。 詳細については、「 CREATE INDEX (Transact-SQL)」を参照してください。

NOEXPAND を使用する

NOEXPAND は、"インデックス付きビュー" にのみ適用されます。 インデックス付きビューとは、一意なクラスター化インデックスが作成されているビューを示します。 インデックス付きビューおよびベース テーブルの両方に存在する列への参照がクエリに含まれていて、クエリ オプティマイザーがクエリの実行にインデックス付きビューを使用する方が最適であると判断した場合、クエリ オプティマイザーはビューのインデックスを利用します。 この機能は、インデックス付きビューのマッチングと呼ばれます。 SQL Server 2016 (13.x) Service Pack 1 より前のバージョンでは、SQL Server の特定のエディションでのみ、クエリ オプティマイザーによるインデックス付きビューの自動的な使用がサポートされています。 すべてのエディションでは、インデックス付きビューの自動使用がサポートされているためです。 また、Azure SQL Database および Azure SQL Managed Instance では、NOEXPAND ヒントを指定しなくても、インデックス付きビューの自動的な使用もサポートされます。

詳細については、「クエリ処理アーキテクチャ ガイド」を参照してください。

Windows の SQL Server の各エディションでサポートされる機能の一覧については、以下を参照してください。

ただし、クエリ オプティマイザーで、インデックス付きビューのマッチングを考慮したり、NOEXPAND ヒントで参照されるインデックス付きビューを使用したりするには、以下の SET オプションを ON に設定する必要があります。

  • ANSI_NULLS
  • ANSI_PADDING
  • ANSI_WARNINGS
  • ARITHABORT 1
  • CONCAT_NULL_YIELDS_NULL
  • QUOTED_IDENTIFIER

1 ARITHABORT は、ANSI_WARNINGS が ON に設定されている場合は、暗黙的に ON に設定されます。 したがって、この設定を手動で調整する必要はありません。

また、NUMERIC_ROUNDABORT オプションは OFF に設定する必要があります。

クエリ オプティマイザーでインデックス付きビューのインデックスを使用するように強制するには、NOEXPAND オプションを指定します。 このヒントは、ビューがクエリ内でも指定されている場合にのみ使用できます。 SQL Server では、FROM 句で直接ビュー名を指定していないクエリで、特定のインデックス付きビューが使用されるようにするヒントは用意されていません。 しかし、クエリ オプティマイザーでは、インデックス付きビューがクエリで直接参照されていなくても、その使用が考慮されます。 NOEXPAND テーブル ヒントを使用すると、SQL Server データベース エンジンでは、インデックス付きビューに関してのみ自動的に統計が作成されます。 このヒントを省略すると、統計の不足に関する実行プランの警告が発生する可能性があります。これは、統計を手動で作成しても解決することはできません。

クエリの最適化中、データベース エンジンでは、クエリでビューが直接参照されたり、NOEXPAND ヒントが使用されたりするときに、自動的に、または手動で作成されたビュー統計を使用します。

テーブル ヒントをクエリ ヒントとして使用する

OPTION (TABLE HINT) 句を使用すると、テーブル ヒントをクエリ ヒントとして指定することもできます。 プラン ガイドのコンテキスト内でのみ、テーブル ヒントをクエリ ヒントとして使用することをお勧めします。 アドホック クエリに対しては、これらのヒントをテーブル ヒントとしてのみ指定します。 詳細については、「 クエリ ヒント (Transact-SQL)」を参照してください。

アクセス許可

KEEPIDENTITY、IGNORE_CONSTRAINTS、IGNORE_TRIGGERS の各ヒントには、テーブルに対する ALTER 権限が必要です。

A. TABLOCK ヒントを使用してロック手法を指定する

次の例では、AdventureWorks2022 データベースの Production.Product テーブルに対する共有ロックを取得し、UPDATE ステートメントの終了まで保持することを指定します。

UPDATE Production.Product
WITH (TABLOCK)
SET ListPrice = ListPrice * 1.10
WHERE ProductNumber LIKE 'BK-%';
GO

B. FORCESEEK ヒントを使用してインデックス シーク操作を指定する

次の例では、インデックスを指定せずに FORCESEEK ヒントを使用して、クエリ オプティマイザーで AdventureWorks2022 データベースの Sales.SalesOrderDetail テーブルに対するインデックス シーク操作を実行するように強制します。

SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK)
    ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO

次の例では、インデックスと共に FORCESEEK ヒントを使用して、クエリ オプティマイザーで、指定したインデックスおよびインデックス列に対してインデックス シーク操作を実行するように強制します。

SELECT h.SalesOrderID, h.TotalDue, d.OrderQty
FROM Sales.SalesOrderHeader AS h
    INNER JOIN Sales.SalesOrderDetail AS d
    WITH (FORCESEEK (PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID (SalesOrderID)))
    ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO

C. FORCESCAN ヒントを使用してインデックス スキャン操作を指定する

次の例では、FORCESCAN ヒントを使って、AdventureWorks2022 データベースの Sales.SalesOrderDetail テーブルにスキャン操作を実行するようクエリ オプティマイザーに強制します。

SELECT h.SalesOrderID, h.TotalDue, d.OrderQty
FROM Sales.SalesOrderHeader AS h
    INNER JOIN Sales.SalesOrderDetail AS d
    WITH (FORCESCAN)
    ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);