テーブル ヒント (Transact-SQL)
テーブル ヒントでは、ロック手法、1 つ以上のインデックス、クエリ処理操作 (テーブル スキャンやインデックスのシークなど)、またはその他のオプションを指定することによって、データ操作言語 (DML) ステートメントが存続する間だけ、クエリ オプティマイザーの既定の動作を無効にします。テーブル ヒントは、DML ステートメントの FROM 句で指定されており、その句で参照されるテーブルまたはビューのみに影響します。
注意 |
---|
通常、SQL Server クエリ オプティマイザーでは、クエリにとって最適な実行プランが選択されるため、ヒントは、経験を積んだ開発者やデータベース管理者が最後の手段としてのみ使用することをお勧めします。 |
適用対象
構文
WITH ( <table_hint> [ [, ]...n ] )
<table_hint> ::=
[ NOEXPAND ] {
INDEX ( index_value [ ,...n ] ) | INDEX = ( index_value )
| FASTFIRSTROW
| FORCESEEK [( index_value ( index_column_name [ ,... ] ) ) ]
| FORCESCAN
| HOLDLOCK
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| READUNCOMMITTED
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
<table_hint_limited> ::=
{
KEEPIDENTITY
| KEEPDEFAULTS
| FASTFIRSTROW
| HOLDLOCK
| IGNORE_CONSTRAINTS
| IGNORE_TRIGGERS
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
引数
WITH ( <table_hint> ) [ [ , ]...n]
いくつかの例外を除き、テーブル ヒントは、WITH キーワードを使って指定した場合にのみサポートされます。かっこで囲む必要があります。重要 WITH キーワードを省略することは推奨されていません。この機能は、Microsoft SQL Server の今後のバージョンで削除される予定です。新規の開発作業では、必ず WITH を指定してください。また、現在このキーワードを省略しているアプリケーションは修正してください。
コンマではなくスペースでヒントを区切ることは推奨されていません。この機能は、Microsoft SQL Server の今後のバージョンで削除される予定です。新規の開発作業では、必ずコンマを指定してください。また、現在コンマを省略しているアプリケーションは修正してください。
WITH キーワードの有無にかかわらず使用できるテーブル ヒントは、NOLOCK、READUNCOMMITTED、UPDLOCK、REPEATABLEREAD、SERIALIZABLE、READCOMMITTED、FASTFIRSTROW、TABLOCK、TABLOCKX、PAGLOCK、ROWLOCK、NOWAIT、READPAST、XLOCK、および NOEXPAND です。これらのテーブル ヒントを WITH キーワードを使用せずに指定するときは、単独で指定してください。たとえば、FROM t WITH (TABLOCK) のようにします。ヒントを他のオプションと一緒に指定する場合は、WITH キーワードを使用して指定する必要があります。たとえば、FROM t WITH (TABLOCK, INDEX(myindex)) のようにします。
この制限は、互換性レベル 90 以上のデータベースに対するクエリでヒントを使用する場合に適用されます。
NOEXPAND
クエリ オプティマイザーがクエリを処理する場合に、インデックス付きビューが展開されず、基になるテーブルがアクセスされないことを指定します。クエリ オプティマイザーは、ビューをクラスター化インデックスを持つテーブルのように取り扱います。NOEXPAND はインデックス付きビューにのみ適用できます。詳細については、「解説」を参照してください。INDEX (index_value [,... n] ) | INDEX = (index_value)
構文 INDEX(index_value) では、クエリ オプティマイザーがステートメントを処理する際に使用する 1 つ以上のインデックスの名前または ID を指定します。一方、構文 INDEX = (index_value) では、単一のインデックス値しか指定できません。クラスター化インデックスがある場合、INDEX(0) はクラスター化インデックスのスキャンを実行し、INDEX(1) はクラスター化インデックスのスキャンまたはシークを実行します。クラスター化インデックスがない場合、INDEX(0) はテーブル スキャンを実行し、INDEX(1) はエラーと見なされます。
1 つのヒント リストの中で複数のインデックスが使用されている場合、重複するものはすべて無視され、リスト内の残りのインデックスを使用してテーブルの行が取得されます。インデックス ヒント内のインデックスの順番は重要です。複数のインデックス ヒントはインデックスの AND 処理も設定し、クエリ オプティマイザーはアクセスされる各インデックスに可能な限り多くの条件を適用します。ヒント インデックスの集合に、クエリで参照される列のすべてが含まれているわけではない場合、SQL Server データベース エンジンがすべてのインデックス列を取得した後で、残りの列を取得するフェッチが実行されます。
注 複数のインデックスを参照するインデックス ヒントが、スター結合のファクト テーブルで使用されている場合、オプティマイザーはそのインデックス ヒントを無視し、警告メッセージを返します。また、インデックス論理和は、インデックス ヒントが指定されたテーブルでは許可されません。
テーブル ヒントで指定できるインデックスの最大数は、非クラスター化インデックス 250 個です。
KEEPIDENTITY
INSERT ステートメントで、BULK オプションが OPENROWSET と一緒に使用されているときにのみ適用できます。インポートしたデータ ファイルの ID 値 (複数可) を ID 列に使用することを指定します。KEEPIDENTITY を指定しない場合、この列の ID 値は確認されるのみでインポートされません。クエリ オプティマイザーは、テーブルの作成時に指定された seed および increment の値を基に一意な値を自動的に割り当てます。
重要 テーブルやビューの ID 列の値がデータ ファイルに含まれておらず、ID 列がテーブルの最終列でもない場合は、その ID 列をスキップする必要があります。詳細については、「フォーマット ファイルを使用したデータ フィールドのスキップ」を参照してください。ID 列のスキップに成功すると、クエリ オプティマイザーは、その ID 列の一意な値を、インポートされたテーブル行に自動的に割り当てます。
このヒントを INSERT ...SELECT * FROM OPENROWSET(BULK...) ステートメントで使用する例については、「データの一括インポート時の ID 値の保持」を参照してください。
テーブルの ID 値の確認については、「DBCC CHECKIDENT (Transact-SQL)」を参照してください。
KEEPDEFAULTS
INSERT ステートメントで、BULK オプションが OPENROWSET と一緒に使用されているときにのみ適用できます。データ レコードにテーブルの列値が含まれていない場合に、NULL の代わりにテーブル列の既定値を挿入することを指定します。
このヒントを INSERT ...SELECT <columns> FROM OPENROWSET(BULK...) ステートメントで使用する例については、「一括インポート中の NULL の保持または既定値の使用」を参照してください。
FASTFIRSTROW
OPTION (FAST 1) に相当します。詳細については、「クエリ ヒント (Transact-SQL)」を参照してください。重要 この機能は、Microsoft SQL Server の次のバージョンで削除されます。新規の開発作業ではこの機能を使用しないようにし、現在この機能を使用しているアプリケーションはできるだけ早く修正してください。
FORCESEEK [ **(index_value(**index_column_name [ ,...n ] )) ]
クエリ オプティマイザーに対し、テーブルやビューのデータへのアクセス パスとしてインデックスのシーク操作のみを使用することを指定します。SQL Server 2008 R2 SP1 以降、インデックス パラメーターも指定できます。インデックス パラメーターを使用して FORCESEEK を指定することは、INDEX ヒントを使用して FORCESEEK を使用することと同じです。ただし、シーク対象のインデックスとシーク操作で考慮するインデックス列の両方を指定することで、クエリ オプティマイザーで使用されるアクセス パスをより詳細に制御できるようになります。index_value
インデックスの名前またはインデックスの ID 値を指定します。インデックス ID 0 (ヒープ) は指定できません。インデックスの名前または ID を返すには、sys.indexes カタログ ビューにクエリを実行します。index_column_name
シーク操作に含めるインデックス列の名前を指定します。少なくとも指定されたインデックス列を使用した場合、クエリ オプティマイザーでは、指定されたインデックスを介したインデックスのシーク操作のみが検討されます。オプティマイザーでは、必要に応じて、追加の列が検討される場合もあります。たとえば、非クラスター化インデックスが指定されている場合、オプティマイザーでは、指定された列に加え、クラスター化インデックスのキー列を使用することもできます。
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 を指定する際は、次のガイドラインと制限が適用されます。
ヒントは、INDEX ヒントまたは別の FORCESEEK ヒントと組み合わせて指定することができません。
少なくとも 1 列を指定する必要があり、その列を先頭のキー列にする必要があります。
追加のインデックス列を指定できますが、キー列は省略できません。たとえば、指定されたインデックスに a、b、および c というキー列が含まれている場合、有効な構文には FORCESEEK (MyIndex (a)) や FORCESEEK (MyIndex (a, b) が含まれます。無効な構文は、FORCESEEK (MyIndex (c)) および FORCESEEK (MyIndex (a, c) です。
ヒント内に指定された列名の順序は、参照先のインデックス内での列の順序と一致させる必要があります。
インデックス キーの定義にない列は、指定できません。たとえば、非クラスター化インデックスでは、定義されたインデックス キー列のみを指定できます。自動的にインデックスに含まれるクラスター化キー列は指定できませんが、オプティマイザーでは使用できます。
(列の追加や削除などで) インデックス定義を変更すると、そのインデックスを参照するクエリに対して変更が必要になる場合があります。
ヒントを使用すると、オプティマイザーでは、テーブル上の空間インデックスまたは XML インデックスが検討されなくなります。
ヒントは、FORCESCAN ヒントと組み合わせて指定することはできません。
パーティション インデックスでは、SQL Server によって暗黙的に追加されたパーティション分割列を FORCESEEK ヒントで指定できません。詳細については、「パーティション インデックスの専用ガイドライン」を参照してください。
注意 インデックス パラメーターを使用して FORCESEEK を指定すると、オプティマイザーで考慮できるプラン数の制限は、パラメーターなしで FORCESEEK を指定した場合よりも多くなります。その結果、"プランを生成できない" というエラーが生じる回数が増加する可能性があります。将来のリリースでは、オプティマイザー内部に対して変更が行われるため、考慮できるプラン数が増加する可能性があります。詳細については、「FORCESEEK テーブル ヒントの使用」を参照してください。
FORCESCAN
SQL Server 2008 R2 SP1 で導入されたこのヒントは、参照されているテーブルやビューへのアクセス パスとしてインデックスのスキャン操作のみを使用するようにクエリ オプティマイザーに指定します。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
INSERT ステートメントで、BULK オプションが OPENROWSET と一緒に使用されているときにのみ適用できます。テーブルに対する制約を一括インポート操作時に無視することを指定します。既定では、INSERT によって CHECK 制約および FOREIGN KEY 制約がチェックされます。一括インポート操作の際に 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
INSERT ステートメントで、BULK オプションが OPENROWSET と一緒に使用されているときにのみ適用できます。テーブルに対して定義されたトリガーを、一括インポート操作時に無視することを指定します。既定では、INSERT はトリガーを適用します。
アプリケーションがいずれのトリガーにも依存しておらず、パフォーマンスの最大化が重要な場合にのみ、IGNORE_TRIGGERS を使用してください。
NOLOCK
READUNCOMMITTED に相当します。詳細については、後の「READUNCOMMITTED」を参照してください。注 UPDATE ステートメントまたは DELETE ステートメントの場合 : この機能は、将来のバージョンの Microsoft SQL Server では削除される予定です。新しい開発作業では、この機能の使用を避け、現在この機能を使用しているアプリケーションは修正するようにしてください。
NOWAIT
テーブルでロックがかかったらすぐにメッセージを返すようにデータベース エンジンを設定します。NOWAIT は、特定のテーブルに SET LOCK_TIMEOUT 0 を指定することに相当します。PAGLOCK
通常使用される行やキーに対する個々のロックまたは単一のテーブル ロックの代わりに、ページ ロックを使用します。既定では、操作に適したロック モードを使用します。SNAPSHOT 分離レベルで実行中のトランザクションにおいてこのオプションを指定しても、UPDLOCK や HOLDLOCK など、ロックが必要な他のテーブル ヒントと組み合わせて指定しない限り、ページ ロックは取得されません。READCOMMITTED
読み取り操作が、ロックまたは行バージョンを使用して、READ COMMITTED 分離レベルのルールに従うことを指定します。データベース オプション READ_COMMITTED_SNAPSHOT が OFF の場合、データベース エンジンはデータの読み取り時に共有ロックを取得し、読み取り操作が完了するとロックを解除します。データベース オプション READ_COMMITTED_SNAPSHOT が ON の場合、データベース エンジンはロックを取得せずに行バージョンを使用します。分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。注 UPDATE ステートメントまたは DELETE ステートメントの場合 : この機能は、将来のバージョンの Microsoft 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 を使用する更新操作や削除操作は、外部キーやインデックス付きビューの読み取り時、またはセカンダリ インデックスの変更時にブロックを行う場合があります。
READPAST は、READ COMMITTED 分離レベルまたは REPEATABLE READ 分離レベルで実行中のトランザクションでのみ指定できます。SNAPSHOT 分離レベルで実行中のトランザクションにおいてこのオプションを指定する場合、UPDLOCK や HOLDLOCK など、ロックが必要な他のテーブル ヒントと組み合わせて指定する必要があります。
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 ヒントを無視します。
注 FROM 句を UPDATE または DELETE ステートメントの対象テーブルに適用する場合、この句での READUNCOMMITTED ヒントおよび NOLOCK ヒントの使用は、将来のバージョンの SQL Server でサポートされなくなる予定です。新しい開発作業ではこのコンテキストでのヒントの使用を避け、現在このヒントを使用しているアプリケーションは変更を検討してください。
次のいずれかを使用することによって、ロックの競合を最小限に抑えながら、コミットされていないデータ変更のダーティ リードからトランザクションを保護することができます。
READ COMMITTED 分離レベル。READ_COMMITTED_SNAPSHOT データベース オプションを ON に設定します。
SNAPSHOT 分離レベル。
分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。
注 READUNCOMMITTED が指定されているときにエラー メッセージ 601 が表示された場合は、デッドロック エラー (1205) を解決するときと同じように解決し、ステートメントを再実行してください。
REPEATABLEREAD
REPEATABLE READ 分離レベルで実行しているトランザクションと同じロック セマンティクスでスキャンを実行することを指定します。分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。ROWLOCK
通常取得されるページ ロックまたはテーブル ロックの代わりに、行ロックを取得することを指定します。SNAPSHOT 分離レベルで実行中のトランザクションにおいてこのオプションを指定しても、UPDLOCK や HOLDLOCK など、ロックが必要な他のテーブル ヒントと組み合わせて指定しない限り、行ロックは取得されません。SERIALIZABLE
HOLDLOCK に相当します。共有ロックがより制限的になります。テーブルまたはデータ ページが不要になったときに、トランザクションが完了しているかどうかにかかわらず共有ロックが解除されるのではなく、共有ロックはトランザクションが完了するまで保持されます。SERIALIZABLE 分離レベルで実行しているトランザクションと同じセマンティクスで、スキャンが実行されます。分離レベルの詳細については、「SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」を参照してください。TABLOCK
取得したロックがテーブル レベルで適用されることを指定します。取得されるロックの種類は、実行されるステートメントによって異なります。たとえば、SELECT ステートメントを実行すると、共有ロックを取得できます。TABLOCK を指定することで、行レベルまたはページ レベルではなくテーブル全体に共有ロックが適用されます。HOLDLOCK も指定してある場合は、テーブル ロックがトランザクション終了まで保持されます。INSERT INTO <対象テーブル> SELECT <列> FROM <ソース テーブル> ステートメントを使用してデータをヒープにインポートするときに、対象テーブルに対して TABLOCK ヒントを指定すると、そのステートメントに対してログ記録とロックの最適化を有効にすることができます。データベース復旧モデルが単純復旧モデルまたは一括ログ復旧モデルに設定されている必要もあります。詳細については、「INSERT (Transact-SQL)」を参照してください。
テーブルにデータをインポートするため、OPENROWSET 一括行セット プロバイダーで TABLOCK を使用すると、対象テーブルへのデータ読み込みを、ログ記録とロックを最適化して、複数のクライアントで同時に行うことができます。詳細については、「一括インポートで最小ログ記録を行うための前提条件」を参照してください。
TABLOCKX
テーブルに排他ロックを使用することを指定します。UPDLOCK
更新ロックを使用することと、これをトランザクション終了まで保持することを指定します。UPDLOCK を使用すると、行レベルまたはページ レベルの読み取り操作のみに更新ロックが適用されます。UPDLOCK を TABLOCK と組み合わせたり、なんらかの理由でテーブル レベルのロックが使用されたりすると、代わりに排他 (X) ロックが取得されます。UPDLOCK を指定すると、READCOMMITTED および READCOMMITTEDLOCK 分離レベル ヒントが無視されます。たとえば、セッションの分離レベルを SERIALIZABLE に設定し、クエリで (UPDLOCK, READCOMMITTED) を指定すると、READCOMMITTED ヒントは無視され、トランザクションは SERIALIZABLE 分離レベルを使用して実行されます。
XLOCK
排他ロックを使用することと、これをトランザクション終了まで保持することを指定します。ROWLOCK、PAGLOCK、または TABLOCK と組み合わせて指定すると、排他ロックは適切な粒度レベルに適用されます。
説明
テーブルがクエリ プランによってアクセスされているのではない場合、テーブル ヒントは無視されます。これは、オプティマイザーがテーブルにまったくアクセスしないことを選択した結果であるか、またはインデックス付きビューが代わりにアクセスされるためである可能性があります。後者の場合、OPTION (EXPAND VIEWS) クエリ ヒントを使用することで、インデックス付きビューへのアクセスを防ぐことができます。
すべてのロック ヒントが、クエリ プランによってアクセスされているすべてのテーブルおよびビュー (ビューで参照されているテーブルおよびビューを含む) に反映されます。また、SQL Server は、対応するロックの一貫性チェックを実行します。
行レベルのロックを取得するロック ヒント ROWLOCK、UPDLOCK、および XLOCK では、実際のデータ行ではなくインデックス キーに対してロックが実行される場合があります。たとえば、テーブルに非クラスター化インデックスがあり、ロック ヒントを使用する SELECT ステートメントがカバーするインデックスによって処理される場合、ベース テーブルのデータ行ではなく、カバーするインデックスのインデックス キーに対してロックが取得されます。
テーブルに計算列があり、その計算列が、別のテーブル内の列にアクセスする式や関数によって計算される場合、そのテーブル上でテーブル ヒントが使用されることはありません。つまり、テーブル ヒントは反映されません。たとえば、クエリ内のテーブルに NOLOCK テーブル ヒントが指定されているものとします。このテーブルには、別のテーブル内の列にアクセスする式と関数の組み合わせで計算される、計算列があります。式と関数で参照されるテーブルが、アクセスされるときに NOLOCK テーブル ヒントを使用することはありません。
SQL Server では、FROM 句内の各テーブルに対して、次の各グループの複数のテーブル ヒントが許可されません。
粒度ヒント: PAGLOCK、NOLOCK、READCOMMITTEDLOCK、ROWLOCK、TABLOCK、TABLOCKX
分離レベル ヒント: HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD、SERIALIZABLE
フィルター選択されたインデックス ヒント
フィルター選択されたインデックスをテーブル ヒントとして使用できますが、クエリで選択する行のすべてがカバーされているわけではない場合、クエリ オプティマイザーからエラー 8622 が返されます。フィルター選択されたインデックス ヒントが無効になる例を次に示します。この例では、フィルター選択されたインデックス FIBillOfMaterialsWithComponentID を作成し、SELECT ステートメントのインデックス ヒントとして使用します。フィルター選択されたインデックスの述語には、ComponentID が 533、324、および 753 のデータ行が含まれています。クエリ述語にも ComponentID が 533、324、および 753 のデータ行が含まれていますが、フィルター選択されたインデックスには存在しない ComponentID 855 および 924 も結果セットに含めるよう拡張されています。したがって、クエリ オプティマイザーはフィルター選択されたインデックス ヒントを使用できず、エラー 8622 が生成されます。詳細については、「フィルター選択されたインデックスのデザイン ガイドライン」を参照してください。
USE AdventureWorks2008R2;
GO
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 の Enterprise Edition および Developer Edition でのみサポートされています。
ただし、オプティマイザーで、インデックス付きビューのマッチングを検討したり、NOEXPAND ヒントで参照されるインデックス付きビューを使用したりするには、以下の SET オプションを ON に設定する必要があります。
ANSI_NULLS |
ANSI_WARNINGS |
CONCAT_NULL_YIELDS_NULL |
ANSI_PADDING |
ARITHABORT1 |
QUOTED_IDENTIFIERS |
1 ARITHABORT は、ANSI_WARNINGS が ON に設定されている場合は、暗黙的に ON に設定されます。したがって、この設定を手動で調整する必要はありません。
また、NUMERIC_ROUNDABORT オプションは OFF に設定する必要があります。
オプティマイザーがインデックス付きビューのインデックスを使用するように強制するには、NOEXPAND オプションを指定します。このヒントは、ビューがクエリ内でも指定されている場合にのみ使用できます。SQL Server では、FROM 句で直接ビューを指定していないクエリで、特定のインデックス付きビューが使用されるようにするヒントは用意されていません。しかし、クエリ オプティマイザーでは、インデックス付きビューがクエリで直接参照されていなくても、その使用が検討されます。
詳細については、「ビューのインデックスの解決」を参照してください。
クエリ ヒントとしてのテーブル ヒントの使用
OPTION (TABLE HINT) 句を使用すると、テーブル ヒントをクエリ ヒントとして指定することもできます。プラン ガイドのコンテキスト内でのみ、テーブル ヒントをクエリ ヒントとして使用することをお勧めします。アドホック クエリに対しては、これらのヒントをテーブル ヒントとしてのみ指定します。詳細については、「クエリ ヒント (Transact-SQL)」を参照してください。
権限
KEEPIDENTITY、IGNORE_CONSTRAINTS、IGNORE_TRIGGERS の各ヒントには、テーブルに対する ALTER 権限が必要です。
例
A. TABLOCK ヒントを使用したロック手法の指定
次の例では、Production.Product テーブルに対して共有ロックを使用することと、このロックを UPDATE ステートメントの終了まで保持することを指定します。
USE AdventureWorks2008R2;
GO
UPDATE Production.Product
WITH (TABLOCK)
SET ListPrice = ListPrice * 1.10
WHERE ProductNumber LIKE 'BK-%';
GO
B. FORCESEEK ヒントを使用したインデックスのシーク操作の指定
次の例では、インデックスを指定せずに FORCESEEK ヒントを使用して、Sales.SalesOrderDetail テーブルに対するインデックスのシーク操作を実行するようにクエリ オプティマイザーを設定します。
USE AdventureWorks2008R2;
GO
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 ヒントを使用して、指定したインデックスおよびインデックス列に対してインデックスのシーク操作を実行するようにクエリ オプティマイザーを設定します。
USE AdventureWorks2008R2;
GO
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
B. FORCECAN ヒントを使用したインデックスのスキャン操作の指定
次の例では、FORCESCAN ヒントを使用して、Sales.SalesOrderDetail テーブルに対するスキャン操作を実行するようにクエリ オプティマイザーを設定します。
USE AdventureWorks2008R2;
GO
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);