SARGable述語をCTEまたは派生テーブルにプッシュできるのはいつですか?


15

土嚢

最高品質のPosts®をブログに取り組んでいる間、私は私が実際に見つかったいくつかのオプティマイザの動作に出くわした腹立たしい興味深いです。私はすぐには説明がありませんが、少なくとも私が満足している説明はありませんので、誰かがスマートになった場合に備えてここに説明します。

追跡する場合は、2013バージョンのStack Overflowデータダンプをこちらから入手できます。コメントテーブルを使用していますが、インデックスが1つ追加されています。

CREATE INDEX [ix_ennui] ON [dbo].[Comments] ( [UserId], [Score] DESC );

クエリ1

このようにテーブルをクエリすると、奇妙なクエリプランが表示されます。

WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score DESC
     )
SELECT *
FROM   x
WHERE  x.Score >= 500;

ナッツ

ScoreのSARGable述部はCTE内にプッシュされません。計画のかなり後の時点でフィルター演算子に含まれています。

ナッツ

これORDER BYは、フィルターと同じ列にあるため、おかしいと思います。

クエリ2

クエリを変更すると、プッシュされます。

WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score >= 500
ORDER BY x.Score DESC;

クエリプランは変更も、ディスクへの無流出して、はるかに高速に実行されます。どちらも同じ結果を生成し、非クラスター化インデックススキャンの述語を使用します。

ナッツ

ナッツ

クエリ3

これは、次のようにクエリを記述するのと同じです。

SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score >= 500
ORDER BY c.Score DESC;

クエリ4

派生テーブルを使用すると、最初のCTEクエリと同じ「悪い」クエリプランが取得されます

SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score DESC ) AS x
WHERE x.Score >= 500;

状況はさらに奇妙になります...

クエリを変更してデータを昇順に並べ替え、フィルターをに変更します<=

この質問を長くしすぎないように、すべてをまとめるつもりです。

問い合わせ

--Derived table
SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score ASC ) AS x
WHERE x.Score <= 500;


--TOP inside CTE
WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score ASC
     )
SELECT *
FROM   x
WHERE  x.Score <= 500;


--Written normally
SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score <= 500
ORDER BY c.Score ASC;

--TOP outside CTE
WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score <= 500
ORDER BY x.Score ASC;

予定

リンクを計画します。

ナッツ

これらのクエリはいずれも非クラスター化インデックスを利用しないことに注意してください。ここで変更されるのはフィルター演算子の位置だけです。いずれの場合も、述部は索引アクセスにプッシュされません。

質問が表示されます!

あるシナリオではSARGable述部をプッシュでき、他のシナリオではプッシュできない理由はありますか?降順でソートされたクエリ内の違いは興味深いですが、それらと昇順の奇妙な違いは違います。

興味のある方のために、以下にインデックスのみのプランを示しますScore

回答:


11

ここにはいくつかの問題があります。

述語をプッシュする TOP

現在、オプティマイザーはTOP、そうすることが安全である限られた場合でも、を過ぎて述部をプッシュすることはできません*。この制限は、述語がより大きいスコープにある質問のすべてのクエリの動作を説明しますTOP

回避策は、手動で書き換えを実行することです。基本的な問題は、窓関数を過ぎた述語押すいます、のような対応する特別な規則がないことを除いてSelOnSeqPrj

私の個人的な意見は、探査ルールは SelOnTop人々がTOP一種の「最適化フェンス」を提供しようとして意図的にクエリを記述したためは未実装のままであるということです。

*一般的に、これは述語が ORDER BY関連付けられ句にTOP不等式の方向がソートの方向と一致する必要があることをます。変換では、SQL ServerでのNULLの並べ替え動作も考慮する必要があります。全体的に、制限はおそらく、この変換が実際には追加の探査努力を正当化するほど十分に有用ではないことを意味します。

原価計算の問題

問題の残りの実行計画が原因の値の分布にコストベースの選択肢として説明することができるScoreカラム(より多くの行= 500 <より= 500>)との効果行目標によって導入しますTOP

たとえば、クエリ:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score <= 500
ORDER BY
    c.Score ASC;

...フィルタで明らかにプッシュされていない述語を含むプランを作成します。

行ゴールによる遅延フィルター

ソートは101行を生成すると推定されることに注意してください。これは、Topによって追加された行ゴールの効果です。これは、ソートとフィルターの推定コストに影響を与え、これがより安価なオプションのように見えます。この計画の推定コストは2401.39ユニットです。

クエリヒントで行の目標を無効にした場合:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score <= 500
ORDER BY
    c.Score ASC
OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL'));

...作成される実行計画は次のとおりです。

行ゴールなしで計画する

述語は残余の非引数可能述語としてスキャンにプッシュされており、計画全体のコストは2402.32ですユニットです。

<= 500述部が行をフィルターで除外することは想定されていないことに注意してください。のよう<= 50に小さい数を選択した場合、オプティマイザは、行の目標効果に関係なく、プッシュされた述語プランを優先します。

クエリの場合Score DESCScore >= 500述語:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score >= 500
ORDER BY
    c.Score DESC;

今述語は非常に選択的であることが予想されるので、オプティマイザの選択するには、述語をプッシュすると、検索で非クラスタ化インデックスを使用します。

選択的述語

繰り返しますが、オプティマイザーは複数の選択肢を検討し、これを通常のように明らかに最も安価なオプションとして選択しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.