web-dev-qa-db-ja.com

ユニオンビューをより効率的に実行するにはどうすればよいですか?

私はパフォーマンスの理由でアクティブテーブルとアーカイブテーブルに分割し、直接フィールドマッピングを使用して、アーカイブプロセスを毎晩実行する大きなテーブル(数千から数億レコード)を持っています。

コードのいくつかの場所で、アクティブテーブルとアーカイブテーブルを結合するクエリを実行する必要があります。ほぼ常に1つ以上のフィールド(両方のテーブルにインデックスを配置している)によってフィルター処理されます。便宜上、次のようなビューがあると理にかなっています。

create view vMyTable_Combined as
select * from MyTable_Active
union all
select * from MyTable_Archive

しかし、次のようなクエリを実行すると

select * from vMyTable_Combined where IndexedField = @val

@valでフィルタリングする前に、ActiveとStoreからeverythingの結合を実行して、パフォーマンスを低下させます。

ユニオンを作成する前に、ユニオンビューの2つのサブクエリをそれぞれ@valでフィルタリングする賢い方法はありますか?

または、私が目的を達成するために提案する他のいくつかのアプローチ、つまり、インデックス付きフィールドによってフィルター処理されたユニオンレコードセットを取得する簡単で効率的な方法があるでしょうか?

編集:実行計画は次のとおりです(実際のテーブル名がここに表示されます):

execution plan

奇妙なことに、アクティブテーブルは実際には正しいインデックス(およびRIDルックアップ)を使用していますが、アーカイブテーブルはテーブルスキャンを実行しています!

8
Shaul Behr

質問に対するコメントは、OPがクエリの開発に使用していたテストデータベースのデータ特性が、運用データベースとは根本的に異なっていることが問題であることを示しています。行数がはるかに少なく、フィルタリングに使用されているフィールドの選択性が不十分でした。

列内の個別値の数が少なすぎる場合、インデックスは十分に選択的ではない可能性があります。この場合、シーケンシャルテーブルスキャンは、インデックスシーク/行ルックアップ操作よりも安価です。通常、テーブルスキャンはシーケンシャルI/Oを多用します。これは、ランダムアクセス読み取りよりもはるかに高速です。

多くの場合、クエリが行の数パーセント以上を返す場合、ランダムI/Oを多用するインデックスシーク/行ルックアップまたは同様の操作よりもテーブルスキャンを実行する方が安価です。

追加するために、私が見つけたもの。もし、するなら:

create view vMyTable_Combined as
select *, 1 AS [Active] from MyTable_Active
union all
select *, 0 AS [Active] from MyTable_Archive

次に、[アクティブ]フィールドでフィルタリングし、他のパーツが読み込まれていないことを確認します。

1