web-dev-qa-db-ja.com

両方のインデックス付きビューのクラスター化インデックスによって内部結合しているときに、クエリプロセッサがFORCESEEKヒントを使用してクエリプランを生成できないのはなぜですか?

以下のクエリでFORCESEEKヒントを使用しようとすると、次のエラーが発生します。

メッセージ8622、レベル16、状態1、行96このクエリでヒントが定義されているため、クエリプロセッサはクエリプランを作成できませんでした。ヒントを指定せず、SET FORCEPLANを使用せずにクエリを再送信します。

SELECT A.IndexedField1
INTO #TEMP
FROM dbo.IndexedView1 AS A WITH (FORCESEEK)
INNER JOIN dbo.IndexedView2 AS B
    ON A.IndexedField1 = B.IndexedField1
    AND A.IndexedField2 = B.IndexedField2

IndexedView1とIndexedView2はどちらもスキーマバインドされたインデックス付きビューであり、IndexedField1、IndexedField2フィールドの両方のビューに一意のクラスター化インデックスがあります。適切かどうかはわかりませんが、クラスター化インデックスのサイズは40バイト(1行あたり)です。

両方のビューが実際にどのように見えるかの例を以下に示します。

SELECT 
    IndexedField1,
    RIGHT(CONVERT(VARCHAR(34), HASHBYTES('MD5', OtherField1 + '||' OtherField2)), 32) AS IndexedField2
FROM dbo.Table1

派手すぎず、ビューのクエリ内にヒントもありません。

これは推定の実行計画です(クエリヒントを使用しようとしない場合): Estimated Execution Plan

2
J.D.

これが再現です。 [documented[〜#〜] noexpand [〜#〜] がないと、インデックス付きビューでFORCESEEKを使用できません。

例えば

drop table if exists table1
drop table if exists table2
go
create table Table1(IndexedField1 int, OtherField1 nvarchar(200), OtherField2 nvarchar(200))
create table Table2(IndexedField1 int, OtherField1 nvarchar(200), OtherField2 nvarchar(200))

go

create view IndexedView1
with schemabinding
as
SELECT 
    IndexedField1,
    RIGHT(CONVERT(VARCHAR(34), HASHBYTES('MD5', OtherField1 + '||' + OtherField2)), 32) AS IndexedField2
FROM dbo.Table1

go

create view IndexedView2
with schemabinding
as
SELECT 
    IndexedField1,
    RIGHT(CONVERT(VARCHAR(34), HASHBYTES('MD5', OtherField1 + '||' + OtherField2)), 32) AS IndexedField2
FROM dbo.Table2

go

create unique clustered index pk_IndexedView1 on IndexedView1(IndexedField1,IndexedField2)
create unique clustered index pk_IndexedView2 on IndexedView2(IndexedField1,IndexedField2)

go

SELECT A.IndexedField1
INTO #TEMP
FROM dbo.IndexedView1 AS A WITH (FORCESEEK)
INNER JOIN dbo.IndexedView2 AS B
    ON A.IndexedField1 = B.IndexedField1
    AND A.IndexedField2 = B.IndexedField2

    /*
Msg 8622, Level 16, State 1, Line 34
Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN.
*/
go
drop table if exists #TEMP

SELECT A.IndexedField1
INTO #TEMP
FROM dbo.IndexedView1  AS A with (noexpand)
INNER JOIN dbo.IndexedView2 AS B with (noexpand)
    ON A.IndexedField1 = B.IndexedField1
    AND A.IndexedField2 = B.IndexedField2

プランで実行:

enter image description here

さらに、NOEXPANDを適用し、プランにビューインデックスのみが含まれるように指定した後、FORCESEEKヒントを使用するか、必要に応じて結合スタイル(MERGE、LOOP、またはHASH)を指定できます。

例えば

SELECT A.IndexedField1
INTO #TEMP
FROM dbo.IndexedView1 AS A WITH (NOEXPAND)
INNER MERGE JOIN dbo.IndexedView2 AS B
    ON A.IndexedField1 = B.IndexedField1
    AND A.IndexedField2 = B.IndexedField2