土嚢
最高品質の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
。