web-dev-qa-db-ja.com

誰かがこのひどいクエリプランを手伝ってくれる?

クエリ:

    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秒かかることに気付きました

7

enter image description here

実行プランは、最初に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により早期に停止します-これは確かに別の計画を提供します。

9
Martin Smith

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)
1
Laughing Vergil