it-swarm-eu.dev

SQL Server Linked Server-Leistung: Warum sind Remote-Abfragen so teuer?

Ich habe zwei Datenbankserver, die über Verbindungsserver verbunden sind. Bei beiden handelt es sich um SQL Server 2008R2-Datenbanken. Die Verbindung zum Verbindungsserver wird über eine reguläre "SQL Server" -Verbindung unter Verwendung des Sicherheitskontexts des aktuellen Logins hergestellt. Die Verbindungsserver befinden sich beide im selben Rechenzentrum, daher sollte die Verbindung kein Problem darstellen.

Ich verwende die folgende Abfrage, um zu überprüfen, welche Werte der Spalte identifier remote verfügbar sind, jedoch nicht lokal.

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

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

In beiden Tabellen befinden sich nicht gruppierte Indizes für die Spalte identifier. Lokal gibt es ungefähr 2,6 Millionen Zeilen, nur 54 aus der Ferne. Bei Betrachtung des Abfrageplans werden jedoch 70% der Ausführungszeit für die "Ausführung der Remote-Abfrage" aufgewendet. Wenn Sie den vollständigen Abfrageplan untersuchen, beträgt die Anzahl der geschätzten lokalen Zeilen 1 Anstatt von 2695380 (Dies ist die Anzahl der geschätzten Zeilen, wenn nur die Abfrage ausgewählt wird, die nach EXCEPT kommt). Execution plan Bei der Ausführung dieser Abfrage dauert es in der Tat lange.

Ich frage mich: Warum ist das so? Ist die Schätzung "nur" weit entfernt oder sind Remote-Abfragen auf Verbindungsservern wirklich so teuer?

15
vstrien

Der Plan, den Sie im Moment haben, scheint mir der optimalste Plan zu sein.

Ich stimme der Behauptung in den anderen Antworten nicht zu, dass die 2,6 Millionen Zeilen an den Remote-Server gesendet werden.

Der Plan sieht für mich so aus, als würde er für jede der 54 von der Remote-Abfrage zurückgegebenen Zeilen eine Indexsuche in Ihrer lokalen Tabelle durchführen, um festzustellen, ob sie übereinstimmt oder nicht. Dies ist so ziemlich der optimale Plan.

Das Ersetzen durch einen Hash-Join oder einen Merge-Join wäre angesichts der Größe der Tabelle kontraproduktiv und das Hinzufügen eines Zwischenprodukts #temp table fügt nur einen zusätzlichen Schritt hinzu, der Ihnen keinen Vorteil zu verschaffen scheint.

10
Martin Smith

Das Herstellen einer Verbindung zu einer Remote-Ressource ist teuer. Zeitraum.

Eine der teuersten Operationen in jeder Programmierumgebung ist network IO (obwohl disk IO neigt dazu, es in den Schatten zu stellen).

Dies gilt auch für Remote-Verbindungsserver. Der Server, der den Remote-Verbindungsserver aufruft, muss zuerst eine Verbindung herstellen, dann muss eine Abfrage auf dem Remote-Server ausgeführt, die Ergebnisse zurückgegeben und die Verbindung geschlossen werden. Dies alles braucht Zeit über das Netzwerk.


Sie sollten Ihre Abfrage auch so strukturieren, dass Sie die Mindestdaten über das Kabel übertragen. Erwarten Sie nicht, dass die Datenbank für Sie optimiert wird.

Wenn ich diese Abfrage schreiben würde, würde ich die entfernten Daten in eine Tabellenvariable (oder in eine temporäre Tabelle) auswählen und diese dann in Verbindung mit der lokalen Tabelle verwenden. Dies stellt sicher, dass nur Daten übertragen werden müssen.

Die Abfrage, die Sie ausführen, kann leicht 2,6 Millionen Zeilen an den Remote-Server senden, um die Klausel EXCEPT zu verarbeiten.

6
Oded

Ich bin kein Experte, aber wenn Sie Union, Except oder Intersect verwenden, müssen Sie nicht "Distinct" verwenden. Abhängig von den Werten aus LocalDb.schema. [TableName] kann die Abfrageleistung verbessert werden.

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

EXCEPT

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

Oded ist richtig, das Leistungsproblem wird durch das Senden der 2,6 Millionen Zeilen an Ihren Remote-Server verursacht.

Um dieses Problem zu beheben, können Sie das Senden der Remote-Daten (54 Zeilen) mithilfe einer temporären oder einer In-Memory-Tabelle erzwingen.

Verwenden einer temporären Tabelle

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

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName
0

Ich denke, Sie sind besser dran, die Remote-Tabelle auf den Server zu replizieren, von dem Sie abfragen, und dann Ihr gesamtes SQL lokal auszuführen.

0
Alen