SQL-Leistungsprobleme bei Remote-Abfragen auf Verbindungsservern


8

Dieser Sproc

create proc dbo.Get_Accounts as
begin
  declare @current_date datetime
  set @current_date = dbo.fn_currdate()

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = @current_date
end

schlägt nach 10 Minuten ständig mit der folgenden Fehlermeldung fehl:

Server: Nachricht 7399, Ebene 16, Status 1, Zeile 1 Der OLE DB-Anbieter 'SQLOLEDB' hat einen Fehler gemeldet. Die Ausführung wurde vom Anbieter beendet, weil ein Ressourcenlimit erreicht wurde. [Vom OLE / DB-Anbieter zurückgegebene Nachricht: Zeitüberschreitung abgelaufen] OLE DB-Fehlerablaufverfolgung [OLE / DB-Anbieter 'SQLOLEDB' ICommandText :: Execute zurückgegeben 0x80040e31: Die Ausführung wurde vom Anbieter abgebrochen, weil ein Ressourcenlimit erreicht wurde.].

Wenn ich jedoch dieselbe Abfrage aus derselben Datenbank (nicht auf der Remote-Datenbank) in einem interaktiven Abfragefenster mit dem fest codierten Datum ausführe:

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = '1/20/2012'

Es kehrt in 30 Sekunden zurück.

Der lokale Server ist SQLSERVER 2008, der Remote-Server ist SQLSERVER 2000.

Wir haben Folgendes ohne Erfolg getan:

  • Der gespeicherte Prozess wurde neu erstellt.
  • sp_recompile auf dem gespeicherten Prozess
  • Statistiken zu dbo.accounts aktualisieren
  • löschte und erstellte die Indizes auf dbo.accounts neu
  • löschte den Index auf dbo.accounts und versuchte es
  • DBCC FREEPROCCACHE & DBCC DROPCLEANBUFFERS auf lokalen und Remote-Servern
  • Neustart des Remote-Servers (keine einfache Option auf dem lokalen Server)

Fragen

  • Kann jemand dieses bizarre Verhalten erklären?
  • Irgendwelche Vorschläge zu anderen Korrekturmöglichkeiten?

Antworten:


11

Sie können das Trace-Flag 7300 aktivieren, wodurch möglicherweise eine detailliertere Fehlermeldung angezeigt wird

Wie viele Zeilen gibt eine repräsentative Abfrage zurück? Wie schnell / zuverlässig ist die Netzwerkverbindung zwischen den beiden Servern?

Es ist möglich, dass die Übertragung eines großen Datensatzes zu lange dauert (zusätzlich zur tatsächlichen Abfragezeit). Sie können den Timeout-Wert erhöhen.

Sie können versuchen, die Timeout-Einstellung wie folgt neu zu konfigurieren:

Stellen Sie das Zeitlimit für die Remote-Anmeldung auf 300 Sekunden ein:

sp_configure 'remote login timeout', 300
go 
reconfigure with override 
go 

Setzen Sie das Zeitlimit für Remote-Abfragen auf 0 (unendliche Wartezeit):

sp_configure 'remote query timeout', 0 
go 
reconfigure with override 
go 

Update : Ab SQL Server 2012 SP1 : Benutzer mit SELECTBerechtigungen können darauf zugreifen, DBCC SHOW_STATISTICSwodurch die Nur-Lese-Leistung auf Verbindungsservern verbessert wird. Ref: https://msdn.microsoft.com/en-us/library/ms174384(v=sql.110).aspx

Update : Sie sagen zu Recht, dass es nicht die Datengröße oder die Verbindungsgeschwindigkeit ist. In meiner nebligen Erinnerung klingelte es und ich erinnerte mich, wo ich es gesehen hatte: Langsam in der Anwendung, schnell in SSMS? (Ein Problem mit Verbindungsservern). Es ist kein Parameter-Sniffing, sondern es fehlen die Statistiken selbst (aufgrund von Berechtigungen), wodurch ein fehlerhafter Abfrageplan verwendet wird:

Sie können sehen, dass die Schätzungen unterschiedlich sind. Als ich als Systemadministrator ausgeführt habe, war die Schätzung 1 Zeile, was eine korrekte Zahl ist, da es in Northwind keine Bestellungen gibt, bei denen die Bestell-ID 20000 überschreitet. Bei der Ausführung als einfacher Benutzer betrug die Schätzung jedoch 249 Zeilen. Wir erkennen diese bestimmte Zahl als 30% von 830 Bestellungen oder als Schätzung für eine Ungleichungsoperation, wenn der Optimierer keine Informationen hat. Bisher war dies auf einen unbekannten Variablenwert zurückzuführen, aber in diesem Fall gibt es keine Variable, die unbekannt sein kann. Nein, es fehlen die Statistiken selbst.

Solange eine Abfrage nur auf Tabellen auf dem lokalen Server zugreift, kann der Optimierer immer auf die Statistiken für alle Tabellen in der Abfrage zugreifen. Es gibt keine zusätzlichen Berechtigungsprüfungen. Dies ist jedoch bei Tabellen auf einem Verbindungsserver anders. Wenn SQL Server auf einen Verbindungsserver zugreift, gibt es kein geheimes Protokoll, das nur für die Kommunikation zwischen Servern verwendet wird. Nein, stattdessen verwendet SQL Server die Standard-OLE DB-Schnittstelle für Verbindungsserver, andere SQL Server-Instanzen, Oracle, Textdateien oder Ihre selbst erstellte Datenquelle und stellt wie jeder andere Benutzer eine Verbindung her. Wie genau Statistiken abgerufen werden, hängt von der Datenquelle und dem betreffenden OLE DB-Anbieter ab. In diesem Fall ist der Anbieter der SQL Server Native Client, der die Statistiken in zwei Schritten abruft. (Sie können dies sehen, indem Sie Profiler auf dem Remote-Server ausführen.) Zunächst führt der Anbieter die Prozedur sp_table_statistics2_rowset aus, die Informationen über die vorhandenen Spaltenstatistiken sowie deren Kardinalität und Dichteinformationen zurückgibt. Im zweiten Schritt führt der Anbieter DBCC SHOW_STATISTICS aus, einen Befehl, der die vollständigen Verteilungsstatistiken zurückgibt. (Wir werden uns diesen Befehl später in diesem Artikel genauer ansehen.) Hier ist der Haken: Um DBCC SHOW_STATISTICS ausführen zu können, müssen Sie Mitglied der Serverrolle sysadmin oder einer der Datenbankrollen db_owner oder db_ddladmin sein.

Und deshalb habe ich unterschiedliche Ergebnisse erzielt. Als Sysadmin wurde die vollständige Verteilungsstatistik angezeigt, aus der hervorgeht, dass keine Zeilen mit der Bestellnummer> 20000 vorhanden sind und die Schätzung eine Zeile betrug. (Denken Sie daran, dass das Optimierungsprogramm niemals Nullzeilen aus Statistiken annimmt.) Bei der Ausführung als einfacher Benutzer schlug DBCC SHOW_STATISTICS jedoch mit einem Berechtigungsfehler fehl. Dieser Fehler wurde nicht weitergegeben, sondern der Optimierer akzeptierte, dass keine Statistiken vorhanden waren, und verwendete Standardannahmen. Da es Kardinalitätsinformationen erhielt, erfuhr es, dass die entfernte Tabelle 830 Zeilen hat, woraus sich die Schätzung von 249 Zeilen ergibt.

Wenn Sie auf ein Leistungsproblem stoßen, bei dem eine Abfrage, die den Zugriff auf einen Verbindungsserver enthält, in der Anwendung langsam ist, aber beim Testen über SSMS schnell ausgeführt wird, sollten Sie immer untersuchen, ob unzureichende Berechtigungen für die entfernte Datenbank die Ursache sein können. (Beachten Sie, dass der Zugriff auf den Verbindungsserver in der Abfrage möglicherweise nicht offenkundig ist, sondern in einer Ansicht ausgeblendet werden kann.) Welche Maßnahmen können Sie ergreifen, wenn Sie feststellen, dass Berechtigungen für die entfernte Datenbank das Problem sind?

  • Sie können die Benutzer zur Rolle db_ddladmin hinzufügen. Da dies ihnen jedoch das Recht gibt, Tabellen hinzuzufügen und zu löschen, ist dies nicht empfehlenswert.

  • Wenn Benutzer eine Verbindung zu einem Remoteserver herstellen, stellen sie standardmäßig eine Verbindung als sie selbst her. Sie können jedoch eine Anmeldezuordnung mit sp_addlinkedsrvlogin einrichten, sodass Benutzer einem Proxy-Konto zuordnen, das Mitglied in db_ddladmin ist. Beachten Sie, dass dieses Proxy-Konto eine SQL-Anmeldung sein muss. Dies ist also keine Option, wenn auf dem Remoteserver die SQL-Authentifizierung nicht aktiviert ist. Auch diese Lösung ist aus Sicherheitsgründen etwas zweifelhaft, obwohl sie besser ist als der vorherige Vorschlag.

  • In einigen Fällen können Sie die Abfrage mit OPENQUERY neu schreiben, um die Auswertung auf dem Remote-Server zu erzwingen. Dies kann besonders nützlich sein, wenn die Abfrage mehrere entfernte Tabellen enthält. (Es kann aber auch nach hinten losgehen, da der Optimierer jetzt noch weniger Statistikinformationen vom Remote-Server erhält.)

  • Sie können natürlich die gesamte Palette an Hinweisen und Plananleitungen verwenden, um den gewünschten Plan zu erhalten.

  • Schließlich sollten Sie sich fragen, ob dieser Verbindungsserverzugriff erforderlich ist. Vielleicht könnten sich die Datenbanken auf demselben Server befinden? Könnten Daten repliziert werden? Eine andere Lösung?


Es werden ungefähr 140.000 Datensätze zurückgegeben. Da es jedoch einwandfrei funktioniert, wenn der Datumswert fest codiert ist, kann ich mir kein E / A- oder Netzwerkproblem vorstellen, das die parametrisierte Version so stark beeinträchtigen würde. Mein Bauch sagt, dass die Abfrage an den Remote-Server übergeben wird und der Remote-Optimierer irgendwie einen schlechten Abfrageplan auswählt, wenn er den Parameter nicht verstehen kann. Aber das erneute Indizieren und Löschen des Caches / der Puffer sollte dies korrigieren (nehme ich an). Ich werde mir die Zeitüberschreitungen ansehen, um zu sehen, ob wir es zumindest schaffen, zurückzukehren. Vielen Dank

1
Ausgezeichnete Antwort und erklärte genau das Problem, das ich hatte, danke. Ich würde hinzufügen, dass laut MSDN ab SQL2012 SP1 Benutzer mit SELECTBerechtigung darauf zugreifen können, DBCC SHOW_STATISTICSwodurch die Nur-Lese-Leistung auf Verbindungsservern verbessert wird, ohne die Sicherheit beeinträchtigen zu müssen.
Steve Pettifer

2

Was passiert, wenn Sie dies versuchen (dh explizit angeben, was auf dem Remote-Server ausgeführt werden soll)?:

select [fields]
into dbo.current_accounts
from OPENQUERY(linkedserver, 'SELECT [fields] FROM database.dbo.accounts where date = ''1/20/2012''');

Ich vermute in Ihrem obigen Fall, dass SQL Server nur die gesamte Tabelle vom Remote-Server abruft und dann die Abfrage lokal ausführt (ich habe dies in der Vergangenheit oft gesehen). Ich bevorzuge es, explizit zu sein (entweder durch Verwendung von OPENQUERY oder durch Erstellen eines SP auf dem Remote-Server), damit keine Verwechslungsgefahr besteht.


1

Da es sich um ein Ressourcenproblem handelt, kann der Speicherpool außerhalb des SQL-Servers, der zum Laden externer Treiber verwendet wird, und die CLR nahe an seiner Grenze liegen. Der Standardwert ist 256 MB. Um dies zu umgehen, schlage ich vor, dass Sie zum SQL Server-Konfigurationsmanager auf der Registerkarte "Erweitert" gehen und die Option -g am Ende der Startparameter.ie; -g1024 hinzufügen und dann den SQL Server-Dienst neu starten. Normalerweise mache ich das, da wir eine große Anzahl von Verbindungsservern verwenden. http://msdn.microsoft.com/en-us/library/ms190737.aspx


1

Ich habe zwei Ideen, die helfen könnten. Ich werde Ihnen auch sagen, dass ich Pech mit Performance-Abfragen gegen Verbindungsserver hatte. Meine erste Empfehlung ist also, es zu vermeiden, wenn Sie können.

Meine erste Idee ist, die gespeicherte Prozedur in der SQL Server 2000-Box zu installieren, wobei sie auf den lokalen Server verweist. Sie können die gespeicherte Prozedur dann remote ausführen.

exec linkedserver.database.dbo.Get_Accounts

Wenn Sie diesen Weg gehen können, sollte dies die Leistung enorm verbessern.

Meine zweite Idee ist, beim Ausführen der gespeicherten Prozedur den geschätzten Abfrageplan zu ermitteln. Zeigt es Ihnen, was so viel Zeit kostet? Ein potenzielles Problem besteht darin, dass das Konto, das Sie auf dem Verbindungsserver verwenden, möglicherweise nicht über ausreichende Berechtigungen verfügt, um die Tabellenstatistik abzurufen (Sie benötigen mehr Berechtigungen für den Verbindungsserver als für den lokalen Server). Und das kann Abfragen unglaublich langsam machen. Sie können mehr über dieses spezielle Problem lesen Sie hier .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.