リンクサーバーを介して接続された2つのデータベースサーバーがあります。どちらもSQL Server 2008R2データベースであり、リンクサーバー接続は、現在のログインのセキュリティコンテキストを使用して、通常の「SQL Server」リンクを介して行われます。リンクされたサーバーは両方とも同じデータセンターにあるため、接続は問題になりません。
次のクエリを使用して、列identifier
のどの値がローカルではなくリモートで利用できるかを確認します。
SELECT
identifier
FROM LinkedServer.RemoteDb.schema.[TableName]
EXCEPT
SELECT DISTINCT
identifier
FROM LocalDb.schema.[TableName]
両方のテーブルには、列identifier
の非クラスター化インデックスがあります。ローカルでは約260万行、リモートではわずか54行です。しかし、クエリプランを見ると、実行時間の70%が「リモートクエリの実行」に費やされています。また、完全なクエリプランを調べる場合、推定されるローカル行の数は1
の代わりに 2695380
(EXCEPT
の後に続くクエリのみを選択した場合の推定行数)。 このクエリを実行すると、確かに時間がかかります。
それは私に不思議に思います:なぜこれがですか?見積もりは "ちょうど"ずれていますか、それともリンクサーバーでのリモートクエリは本当にそれほど高価ですか?
あなたが現在持っている計画は、私にとって最適な計画のようです。
他の回答が2.6M行をリモートサーバーに送信しているというアサーションに同意しません。
計画では、リモートクエリから返された54行のそれぞれについて、ローカルテーブルへのインデックスシークを実行して、一致するかどうかを判断しているように見えます。これはかなり最適な計画です。
ハッシュ結合またはマージ結合で置き換えることは、テーブルのサイズを考えると逆効果であり、中間の#temp
テーブルを追加することは、利点をもたらすとは思われない追加のステップを追加するだけです。
リモートリソースへの接続にはコストがかかります。限目。
あらゆるプログラミング環境で最もコストのかかる操作の1つは、ネットワークIOです(ただし、ディスクIOはそれを小さくする傾向があります)。
これは、リモートリンクサーバーにまで及びます。リモートリンクサーバーを呼び出すサーバーは、最初に接続を確立する必要があります。次に、リモートサーバーでクエリを実行し、結果を返し、接続を閉じます。これにはすべてネットワーク経由で時間がかかります。
また、最小限のデータをネットワーク経由で転送するようにクエリを構成する必要があります。 DBが最適化することを期待しないでください。
このクエリを作成する場合、リモートデータをテーブル変数(または一時テーブル)に選択し、これをローカルテーブルと組み合わせて使用します。これにより、転送が必要なデータのみが転送されます。
実行しているクエリは、EXCEPT
句を処理するために、リモートサーバーに260万行を簡単に送信できます。
私は専門家ではありませんが、Union、Except、またはIntersectを使用している場合は、「Distinct」を使用する必要はありません。 LocalDb.schema。[TableName]の値によっては、クエリのパフォーマンスを向上させることができます。
SELECT
identifier
FROM LinkedServer.RemoteDb.schema.[TableName]
EXCEPT
SELECT
identifier
FROM LocalDb.schema.[TableName]
Odedは正解です。パフォーマンスの問題は、2.6Mの行をリモートサーバーに送信することで発生します。
この問題を解決するには、一時テーブルまたはメモリ内テーブルを使用して、リモートデータ(54行)を強制的に送信できます。
一時テーブルを使用
SELECT identifier
INTO #TableName
FROM LinkedServer.RemoteDb.schema.[TableName]
SELECT identifier
FROM #TableName
EXCEPT
SELECT DISTINCT identifier
FROM LocalDb.schema.[TableName]
DROP #TableName
リモートテーブルをクエリ元のサーバーにレプリケートし、すべてのSQLをローカルで実行する方がよいと思います。