ドキュメントは少し誤解を招くものです。DMVは非具体化ビューであり、そのような主キーはありません。基礎となる定義は少し複雑ですが、以下の簡略化された定義sys.query_store_plan
は次のとおりです。
CREATE VIEW sys.query_store_plan AS
SELECT
PPM.plan_id
-- various other attributes
FROM sys.plan_persist_plan_merged AS PPM
LEFT JOIN sys.syspalvalues AS P
ON P.class = 'PFT'
AND P.[value] = plan_forcing_type;
さらに、sys.plan_persist_plan_merged
もビューですが、その定義を確認するには専用管理者接続を介して接続する必要があります。再度、簡略化しました:
CREATE VIEW sys.plan_persist_plan_merged AS
SELECT
P.plan_id as plan_id,
-- various other attributes
FROM sys.plan_persist_plan P
-- NOTE - in order to prevent potential deadlock
-- between QDS_STATEMENT_STABILITY LOCK and index locks
WITH (NOLOCK)
LEFT JOIN sys.plan_persist_plan_in_memory PM
ON P.plan_id = PM.plan_id;
インデックスsys.plan_persist_plan
は次のとおりです。
╔════════════════════════╦════════════════════════ ══════════════╦═════════════╗
║index_name║index_description║index_keys║
╠════════════════════════╬════════════════════════ ══════════════╬═════════════╣
║plan_persist_plan_cidx║クラスタ化された一意のPRIMARYにあります║plan_id║
║plan_persist_plan_idx1 PR PRIMARYにある非クラスター║query_id(-)║
╚════════════════════════╩════════════════════════ ══════════════╩═════════════╝
したがってplan_id
、はで一意になるように制約されていsys.plan_persist_plan
ます。
これsys.plan_persist_plan_in_memory
はストリーミングテーブル値関数であり、内部メモリ構造にのみ保持されているデータを表形式で表示します。そのため、固有の制約はありません。
したがって、実行されるクエリは、本質的には次と同等です。
DECLARE @t1 table (plan_id integer NOT NULL);
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT
T1.plan_id
FROM @t1 AS T1
LEFT JOIN
(
SELECT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id
) AS Q1
ON Q1.plan_id = T1.plan_id;
...これは結合の削除を生成しません:
問題の核心を正しく理解すると、問題は内部クエリです。
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id;
...に一意性の制約がない@t2
ため、左結合では行が重複する可能@t3
性がありますplan_id
。したがって、結合は削除できません。
これを回避するために、重複するplan_id
値を必要としないことをオプティマイザに明示的に伝えることができます。
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT DISTINCT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id;
への外部結合を@t3
削除できるようになりました。
それを実際のクエリに適用する:
SELECT DISTINCT
T.plan_id
FROM #tears AS T
LEFT JOIN sys.query_store_plan AS QSP
ON QSP.plan_id = T.plan_id;
同様に、のGROUP BY T.plan_id
代わりに追加できDISTINCT
ます。とにかく、オプティマイザplan_id
はネストされたビュー全体にわたって属性について正しく推論できるようになり、必要に応じて両方の外部結合を削除できます。
plan_id
一時テーブルで一意にすることは、誤った結果を排除しないため、結合の排除を行うのに十分ではないことに注意してください。plan_id
ここでオプティマイザがその魔法を働かせるには、最終結果からの重複値を明示的に拒否する必要があります。