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


14

リンクサーバー経由で接続された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%が「リモートクエリの実行」に費やされています。また、完全なクエリプランを調べる場合、推定ローカル行の数12695380(の後に来るクエリのみを選択した場合の推定行の数)の代わりになりますEXCEPT実行計画 このクエリを実行すると、実際に時間がかかります。

不思議に思う:これはなぜですか?推定値は「ちょうど」外れていますか、それともリンクサーバーでのリモートクエリは本当にそれほど高価ですか?


2
ところで:それはあなたがインデックスシークのために見なければならない「推定実行数」です。推定行数は、実行ごとに出力される行であり、プランにフルスキャンがない限り、テーブル自体の行数には関係しません。
マーティンスミス

回答:


9

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

2.6M行をリモートサーバーに送信しているという他の回答の主張には同意しません。

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

ハッシュ結合またはマージ結合で置き換えると、テーブルのサイズを考えると逆効果になり、中間#tempテーブルを追加すると、利点が得られないように見える追加の手順が追加されるだけです。


6

リモートリソースへの接続は高価です。限目。

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

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


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

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

実行中のクエリは、EXCEPT節を処理するために、簡単に2.6M行をリモートサーバーに送信できます。


わかりましたので、接続をセットアップするための起動コストが高くなります。クエリを送信し、リモートで処理する必要があり(そのためにネットワークは必要ありません)、最後に結果を返送して処理する必要があります。しかし、ネットワーク接続を介してデータを送信するのに数分かかることはありませんか?
-vstrien

@vstrien-可能性があります。ネットワーク接続、遅延、飽和、およびその他の要因に依存します。ポイントがある-それは決定論的ではありません。

@vstrien-私の答えに詳細を追加しました。記述されたクエリは、処理のためにリモートサーバーにローカル行を送信すると考えています。

2
2.6M行をリモートサーバーに送信しているという事実はどこから推測できますか?リモートクエリ演算子を使用した計画の経験はあまりありませんが、リモートクエリ演算子から54行が出ているように見え、ローカルテーブルに対してアンチセミジョインを実行しています。
マーティンスミス

2
@Lieven-論理的かもしれませんが、示されている計画から正しいとは思わないでください。
マーティンスミス

1

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

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

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]

0

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

一時テーブルを使用すると、どのような場合でもカーディナリティの推定に役立つ場合がありますが、ネストされたループは54行のみに対して妥当と思われます。
マーティンスミス

一時テーブルを使用すると、54行で正しく機能します。しかし、両側に大きなテーブルがある場合は、もう実行できません。同じサイズの2つの「巨大な」テーブルに対するソリューションは何でしょうか?別のデータベースにUserTableを作成しますか?
-vstrien

1
@vstrien-2つの同じサイズの巨大なテーブルには、本当に良い解決策はありません。おそらく、分散パーティションビューを作成することは興味がありますが、私はまったく経験がありません。
リーベンキースマエカーズ

0

リモートテーブルをクエリ元のサーバーに複製してから、すべてのSQLをローカルで実行した方が良いと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.