私は次のクエリを最適化しようとしています(実際にはもう少し複雑ですが、これは重要な部分です):
SELECT Id, StatusDate, [...Lot Of Columns...]
FROM ( (
SELECT Id, StatusDate, [...Lot Of Columns...]
FROM Results_201505
WHERE A = 0, B = 1, C = 3
) UNION ALL (
SELECT Id, StatusDate, [...Lot Of Columns...]
FROM Results_201504
WHERE A = 0, B = 1, C = 3
) UNION ALL (
SELECT Id, StatusDate, [...Lot Of Columns...]
FROM Results_201503
WHERE A = 0, B = 1, C = 3
)
) as result
ORDER BY StatusDate DESC
OFFSET xxx ROWS
FETCH NEXT 25 ROWS ONLY
すべてのテーブルで、「where」の部分をカバーするインデックスを作成しました。
CREATE NONCLUSTERED INDEX ix_asdf ON Results_asdf (StatusDate DESC)
INCLUDE (A, B, C)
WHERE
の条件は、ユーザーが選択したフィルターによって変化するため、インデックスA, B, C, StatusDate
を使用できません。 WHERE A=, B=, C=
にすることもできますが、WHERE B=, D=
またはWHERE C=
にすることも、WHERE
なしにすることもできます)。
私の考えでは、SQL Serverは私のインデックスを使用して高速インデックススキャンを実行し、キールックアップを可能な限り最後の瞬間(上位25行をフェッチする)まで遅らせます。これは、最も合理的な方法のように思えます。
実際、[... Lot of Columns...]
をコメントアウトすると、すべてが計画どおりに進みます。インデックスが使用され、キーの検索は不要で、すべてが非常に高速です。
ただし、完全な形式では、SQL Server(SSMSで示されている実行プランによる)は、OFFSET ... FETCH 25
の前にキールックアップを実行しようとします各行に対して。
理由は明らかです(私は信じています)-Sql Serverは、UNION ALL
が複数のテーブルを連結していることを認識しているため、UNION
の後、キールックアップを実行するには遅すぎます(UNION
SQL Serverが認識しているため) ID
のみですが、どの結果テーブルからのものかはわかりません)。 ID
はグローバルに一意ですが、クエリオプティマイザはおそらくそれを認識していません。
もちろん、次のような方法でこれを回避することができます。
SELECT Id, StatusDate, [ some way to select columns from appropiate table depending on result.tbl ]
FROM (
(
SELECT Id, StatusDate, 'Results_201505' as tbl
FROM Results_201505
WHERE A = 0, B = 1, C = 3
) UNION ALL (
SELECT Id, StatusDate, 'Results_201504' as tbl
FROM Results_201504
WHERE A = 0, B = 1, C = 3
) UNION ALL (
SELECT Id, StatusDate, 'Results_201503' as tbl
FROM Results_201503
WHERE A = 0, B = 1, C = 3
)
) as result
ORDER BY StatusDate DESC
OFFSET xxx ROWS
FETCH NEXT 25 ROWS ONLY
しかし、私の質問は-より良い方法はありますか?オプティマイザーへのある種のヒントは完璧ですが、それが不可能な場合、このクエリを処理するための最もエレガント/最速/最良の方法は何ですか?
これを試しましたか?
SELECT Id, StatusDate, [ some way to select columns from appropiate table depending on result.tbl ]
FROM (
SELECT Id, StatusDate, 'Results_201505' as tbl
FROM Results_201505
WHERE A = 0, B = 1, C = 3
UNION ALL
SELECT Id, StatusDate, 'Results_201504' as tbl
FROM Results_201504
WHERE A = 0, B = 1, C = 3
UNION ALL
SELECT Id, StatusDate, 'Results_201503' as tbl
FROM Results_201503
WHERE A = 0, B = 1, C = 3
ORDER BY StatusDate DESC
OFFSET xxx ROWS
FETCH NEXT 25 ROWS ONLY
) AS result ;
ここで最も重要な最適化は、実際のクエリプランにCONVERT_IMPLICIT演算子が含まれていないことを確認することです。これは、UNIONALLされているテーブル間でわずかに異なるデータ型がある場合に発生する可能性があります。これにより、パフォーマンスが10倍から100倍低下する可能性があります。
最後の25行のみを取得する場合は、それぞれに25行のみを挿入する一時テーブルを作成できます。次に、FETCHは合計75の「ベスト25」を取得します(3つのテーブルがそれぞれ25行で結合されます)。
または、Enterprise Editionを使用している場合は、インデックス付きのパーティションビューを作成できます。