web-dev-qa-db-ja.com

SQL Serverリンクサーバーのパフォーマンス:なぜリモートクエリはそれほど高価なのですか?

リンクサーバーを介して接続された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 の代わりに 2695380EXCEPTの後に続くクエリのみを選択した場合の推定行数)。 Execution plan このクエリを実行すると、確かに時間がかかります。

それは私に不思議に思います:なぜこれがですか?見積もりは "ちょうど"ずれていますか、それともリンクサーバーでのリモートクエリは本当にそれほど高価ですか?

15
vstrien

あなたが現在持っている計画は、私にとって最適な計画のようです。

他の回答が2.6M行をリモートサーバーに送信しているというアサーションに同意しません。

計画では、リモートクエリから返された54行のそれぞれについて、ローカルテーブルへのインデックスシークを実行して、一致するかどうかを判断しているように見えます。これはかなり最適な計画です。

ハッシュ結合またはマージ結合で置き換えることは、テーブルのサイズを考えると逆効果であり、中間の#tempテーブルを追加することは、利点をもたらすとは思われない追加のステップを追加するだけです。

10
Martin Smith

リモートリソースへの接続にはコストがかかります。限目。

あらゆるプログラミング環境で最もコストのかかる操作の1つは、ネットワークIOです(ただし、ディスクIOはそれを小さくする傾向があります)。

これは、リモートリンクサーバーにまで及びます。リモートリンクサーバーを呼び出すサーバーは、最初に接続を確立する必要があります。次に、リモートサーバーでクエリを実行し、結果を返し、接続を閉じます。これにはすべてネットワーク経由で時間がかかります。


また、最小限のデータをネットワーク経由で転送するようにクエリを構成する必要があります。 DBが最適化することを期待しないでください。

このクエリを作成する場合、リモートデータをテーブル変数(または一時テーブル)に選択し、これをローカルテーブルと組み合わせて使用​​します。これにより、転送が必要なデータのみが転送されます。

実行しているクエリは、EXCEPT句を処理するために、リモートサーバーに260万行を簡単に送信できます。

6
Oded

私は専門家ではありませんが、Union、Except、またはIntersectを使用している場合は、「Distinct」を使用する必要はありません。 LocalDb.schema。[TableName]の値によっては、クエリのパフォーマンスを向上させることができます。

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]
1
joakon

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
0

リモートテーブルをクエリ元のサーバーにレプリケートし、すべてのSQLをローカルで実行する方がよいと思います。

0
Alen