Ich habe zwei Datenbankserver, die über Verbindungsserver verbunden sind. Bei beiden handelt es sich um SQL Server 2008R2-Datenbanken, und die Verbindung zum Verbindungsserver wird über eine reguläre "SQL Server" -Verbindung hergestellt, wobei der Sicherheitskontext des aktuellen Logins verwendet wird. Die Verbindungsserver befinden sich beide im selben Rechenzentrum, sodass die Verbindung kein Problem darstellen sollte.
Ich benutze die folgende Abfrage, um zu überprüfen, welche Werte der Spalte identifier
remote, aber nicht lokal verfügbar sind.
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 sind es etwa 2,6 Millionen Zeilen, nur im Remote-Zugriff 54. Bei Betrachtung des Abfrageplans werden jedoch 70% der Ausführungszeit für "Ausführen von Remote-Abfragen" verwendet. Beim Studium des vollständigen Abfrageplans wird 1
stattdessen die Anzahl der geschätzten lokalen Zeilen angegeben 2695380
(dies ist die Anzahl der geschätzten Zeilen, wenn nur die nachfolgende Abfrage ausgewählt wird EXCEPT
).
Die Ausführung dieser Abfrage dauert in der Tat sehr lange.
Ich frage mich: Warum ist das so? Ist die Schätzung "nur" weg oder sind Remote-Abfragen auf Verbindungsservern wirklich so teuer?
Antworten:
Der Plan, den Sie im Moment haben, scheint mir der optimalste zu sein.
Ich bin mit der Behauptung in den anderen Antworten nicht einverstanden, dass es die 2.6M Reihen zum Fernbediener sendet.
Der Plan sieht für mich so aus, als würde für jede der 54 von der Remote-Abfrage zurückgegebenen Zeilen eine Indexsuche in Ihrer lokalen Tabelle durchgeführt, um festzustellen, ob eine Übereinstimmung vorliegt 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 einer Zwischentabelle
#temp
fügt lediglich einen zusätzlichen Schritt hinzu, der Ihnen keinen Vorteil zu bringen scheint.quelle
Das Herstellen einer Verbindung zu einer Remote-Ressource ist teuer. Zeitraum.
Eine der teuersten Operationen in jeder Programmierumgebung ist die Netzwerk-E / A (obwohl die Festplatten-E / A dazu neigt, sie in den Schatten zu stellen).
Dies gilt auch für Remote-Verbindungsserver. Der Server, der den Remote-Verbindungsserver aufruft, muss zuerst eine Verbindung herstellen. Anschließend 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 minimalen Daten über die Leitung übertragen. Erwarten Sie nicht, dass die DB für Sie optimiert.
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, die übertragen werden müssen.
Die Abfrage, die Sie ausführen, kann problemlos 2.6M Zeilen an den Remote-Server senden, um die
EXCEPT
Klausel zu verarbeiten .quelle
Ich bin kein Experte, aber wenn Sie Union, Except oder Intersect verwenden, müssen Sie "Distinct" nicht verwenden. Abhängig von den Werten aus LocalDb.schema. [TableName] kann die Abfrageleistung verbessert werden.
quelle
Oded ist richtig, das Leistungsproblem wird durch das Senden der 2.6M-Zeilen an Ihren Remote-Server verursacht.
Um dieses Problem zu beheben, können Sie das Senden der Remote-Daten (54 Zeilen) erzwingen, indem Sie eine temporäre oder eine In-Memory-Tabelle verwenden.
Temporäre Tabelle verwenden
quelle
Ich denke, Sie sind besser dran, die entfernte Tabelle auf den Server zu replizieren, den Sie abfragen, und dann all Ihre SQL-Anweisungen lokal auszuführen.
quelle