クエリ:
SELECT Object1.Column1, Object2.Column2 AS Column3, Object2.Column4 AS Column5,
Object3.Column6, Object3.Column7,Object1.Column8, Object1.Column9,
Object1.Column10, Object1.Column11, Object1.Column12, Object1.Column13,
Object1.Column14, Object1.Column15 as Column15, Object1.Column16,
Object4.Column4 AS Column17, Object4.Column2 AS Column18, Object1.Column19,
Object1.Column20, Object1.Column21, Object1.Column22, Object1.Column23,
Object1.Column24, Object1.Column25, Object1.Column26, Object5.Column4,
Object1.Column27, Object1.Column28, Object1.Column29, Object3.Column30,
Object3.Column1 as Column31, Object3.Column32 as Column33, Object1.Column34
as Column34, ? AS Column35 , Object3.Column36 as Column37
FROM Object6 AS Object1
INNER JOIN Object7 AS Object3 ON Object1.Column38 = Object3.Column1
INNER JOIN Object8 AS Object2 ON Object3.Column30 = Object2.Column1
LEFT JOIN Object9 AS Object4 ON Object1.Column16 = Object4.Column2
LEFT JOIN Object10 AS Object5 ON Object1.Column9 = Object5.Column2
WHERE Object2.Column1 <> ? AND Object1.Column8 = ?
AND ( coalesce(Column16,?)= ? )
AND EXISTS (
SELECT ?
FROM Object11
WHERE Column39 = ?
AND Column30 = Object3.Column30)
ORDER BY Column7 desc
OFFSET ? ROWS FETCH FIRST ? ROWS ONLY
私はこれにインデックスを追加する必要があることを知っています:
Database1.Schema1.Object7.Column30、Database1.Schema1.Object7.Column36、Database1.Schema1.Object7.Column6、Database1.Schema1.Object7.Column32
しかし、この列の1つはvarchar 4000であり、フィールドの大きなディメンションの原因を作成することはできません。
返された行が最初のフェッチ数よりも少ない場合にのみ、25秒かかることに気付きました
実行プランは、最初にObject7
にアクセスします。非カバーインデックスをColumn7
の順序で使用します。次に、そのテーブルに対していくつかのキールックアップを行い、他のテーブルに対してネストされたループ結合を行います。最終的に結合された結果は、__ some $ code__で順序付けられたTOP
演算子に到達します。
これがColumn7
を満たすのに十分な行を受信すると、下流の演算子からの行の要求を停止できます。 SQL Serverは、このポイントに到達する前に、OFFSET ... FETCH
の初期インデックスから2419行を読み取るだけでよいと推定しています。
この見積もりはまったく正しくありません。実際、Object7.Column7
全体を読み取ることになり、Object7
が満たされる前に行が不足する可能性があります。
OFFSET ... FETCH
の準結合は行数をほぼ半分に減らしますが、キラーはObject11
の結合であり、同じテーブルの述語です。これらにより、準結合からObject6
への9,753,116
行が2
に削減されます。
これらの結合からカーディナリティの推定値をより正確に取得するために、関連するテーブルの統計を確認するのに少し時間をかけるか、またはOPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL') )
を追加して、計画にコストがかかることを想定せずにコストをかけることができます。 OFFSET ... FETCH
により早期に停止します-これは確かに別の計画を提供します。
Object7のCREATE INDEX
ステートメントのINCLUDE
部分のObject7の他のフィールドを使用して、Object11、Column39 + Column30、およびObject7、Column30にインデックスを追加できる場合、パフォーマンスが大幅に向上するはずです。 。これは、このクエリに関連するリソース消費の大部分です。
プランのXMLに基づいて、これらはこのクエリに最適なインデックスに近いように見えます。
CREATE INDEX Idx_Object11_Column39_Column30
ON Object11(Column39_Column30)
CREATE INDEX Idx_Object7_Column30_Column1_Includes
ON Object7 (Column30, Column1)
INCLUDE (Column7, Column36, Column6, Column2)