Abfrage läuft unter SQL 2005 anders als unter SQL 2008R2

9

In meinem Büro haben wir eine Abfrage, die ziemlich hässlich ist, aber in der Produktion und in der Entwicklungsumgebung (20 Sekunden bzw. 4 Sekunden) ziemlich gut läuft. In unserer Testumgebung dauert es jedoch mehr als 4 Stunden. SQL2005 (+ neueste Patches) wird in Produktion und Entwicklung ausgeführt. SQL2008R2 wird getestet.

Ich habe mir den Abfrageplan angesehen und er zeigt, dass SQL2008R2 TempDB über einen Table Spool (Lazy Spool) verwendet, um die zurückgegebenen Zeilen vom Verbindungsserver zu speichern. Der nächste Schritt besteht darin, dass verschachtelte Schleifen (linker Anti-Semi-Join) 96,3% der Abfrage verschlingen. Die Leitung zwischen den beiden Betreibern liegt bei 5.398 MB!

Der Abfrageplan für SQL 2005 zeigt keine Verwendung von Tempdb und keine Verwendung eines Left Anti Semi Join.

Unten finden Sie den bereinigten Code und die Ausführungspläne für den Plan 2005 oben und den Plan 2008R2 unten.

Was verursacht die drastische Verlangsamung und Veränderung? Ich hatte erwartet, einen anderen Ausführungsplan zu sehen, was mich also nicht stört. Die dramatische Verlangsamung der Abfragezeit macht mir Sorgen.

Muss ich mir die zugrunde liegende Hardware ansehen, da die 2008R2-Version Tempdb verwendet, muss ich mir ansehen, wie ich die Nutzung dieser Hardware optimieren kann?

Gibt es eine bessere Möglichkeit, die Abfrage zu schreiben?

Danke für die Hilfe.

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: EDIT :: Die Abfrage wurde von einer anderen SQL2005-Instanz ausgeführt, so ziemlich dem gleichen Ausführungsplan wie der "gute". Ich bin mir immer noch nicht sicher, wie die beiden 2005-Versionen auf dem 2008R2-Verbindungsserver besser ausgeführt werden als die 2008R2-Instanzen auf den 2008R2-Instanzen.

Ich leugne zwar nicht, dass der Code etwas Arbeit gebrauchen könnte, aber wenn der Code das Problem wäre, würde ich dann nicht in allen meinen Versuchen die gleichen Exec-Pläne sehen? Unabhängig von der SQL-Version?

:: EDIT :: Ich habe SP1 und CU3 auf beide 2008R2-Instanzen angewendet, immer noch keine Würfel. Ich habe speziell die Kollokation im Verbindungsserver festgelegt, keine Würfel. Ich habe speziell festgelegt, dass die Berechtigungen meines Benutzerkontos in beiden Fällen sysadmin sind, keine Würfel. Ich habe mich auch an meine SQL Server 2008-Interna und die Fehlerbehebung erinnert. Wir werden sehen, ob ich dies irgendwie nachverfolgen kann.

Vielen Dank an alle für die Hilfe und die Tipps.

:: EDIT :: Ich habe verschiedene Berechtigungsänderungen am Verbindungsserver vorgenommen. Ich habe SQL-Anmeldungen und Domänenanmeldungen verwendet. Ich habe mich als Benutzer ausgegeben. Ich habe die Option "Mit diesem Sicherheitskontext erstellt werden" verwendet. Ich habe Benutzer auf beiden Seiten des Verbindungsservers erstellt, die über Systemadministratorrechte auf dem Server verfügen. Ich habe keine Ideen mehr.

Ich würde immer noch gerne wissen, warum SQL2005 die Abfrage so dramatisch von SQL2008R2 unterscheidet. Wenn die Abfrage fehlerhaft wäre, würde die Laufzeit von 4+ Stunden sowohl auf SQL2005 als auch auf SQL2008R2 angezeigt.

RateControl
quelle

Antworten:

5

Ich möchte, dass Sie die Abfrage überarbeiten.

Sie haben Probleme mit der Sargabilität und verwenden dort sogar skalare Funktionsaufrufe, die auch die Abfrage beeinträchtigen. Möglicherweise möchten Sie eine berechnete FullName-Spalte in Tabelle 2 erstellen und einen Index darauf setzen, um sicherzustellen, dass Ihr Index Vorname und Nachname enthält. Sie sollten auch Indizes hinzufügen, die dem anderen helfen

Erstellen Sie außerdem eine Inline-Tabellenwertfunktion, um Ihre "RemoveNonLetter" -Funktionalität auszuführen, und überarbeiten Sie Ihre Abfrage, um diese zu verwenden, wahrscheinlich mit APPLY, wie ich es hier getan habe.

Und überprüfen Sie auf jeden Fall den Fehler, auf den sich Pauls Antwort bezieht.

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;
Rob Farley
quelle
6

Zusätzlich zu den bisherigen Antworten, der Grund für den Plan Regression könnte sein , aufgrund eines bekannten Mächtigkeit Schätzung Fehler , wenn der Plan ein Anti enthält Semi Join. Siehe KB 2222998

Angenommen, der Plan für 2005 hat eine akzeptable Leistung erbracht. Wenn Sie den Server auf eine Version bringen, die diesen Fix enthält (und TF4199 aktiviert), kehren Sie zum "guten" Plan zurück.

Es gibt jedoch viele andere Möglichkeiten, diese Abfrage zu verbessern. Daher ist dies möglicherweise ein guter Zeitpunkt, um sich stattdessen darauf zu konzentrieren.

Paul White 9
quelle
5

Ich würde vorschlagen, dass die entfernten Daten lokal gespoolt werden, weil einer von

  1. Die Einstellungen für den Verbindungsserver (z. B. Sortierung) sind nicht identisch
  2. Die lokale Sortierung ist trotz der Einstellungen für den Verbindungsserver nicht mit der Remote-Sortierung identisch
  3. Die Abfrage kann aufgrund von Berechtigungen nicht ordnungsgemäß remote ausgeführt werden

Zu Punkt 1 siehe sp_serveroption
und zu Punkt 2, aber auch Server / Datenbank-Kollatierungen überprüfen.

Für Punkt 3 siehe diese von Linchi Shea:

Sie fordern SQL Server auf, alle Daten gemäß meiner Antwort hier lokal zu verarbeiten: Auswirkungen der Verwendung von OPENQUERY in einer Ansicht auf die Leistung

Bearbeiten

Auf den zweiten Blick sehe ich 2 Fernanrufe auf dem "guten" Plan und nicht einen. Dies bestätigt, was ich hier sage

gbn
quelle
Entschuldigung für die lange Verzögerung. 1: Ich habe die Einstellungen des Verbindungsservers überprüft. Sie sind dieselben. 2: Ich habe auch die Sortierung der Eigenschaften des Verbindungsservers auf dem Remoteserver überprüft und implizit festgelegt. 3: Der Sicherheitskontext, an dem ich noch arbeite, führt A / B-Tests durch. Ich bin immer noch auf der Suche nach der Logik hinter den drastisch unterschiedlichen Exec-Plänen. Vom R2-Server zum R2-Server wird nur die Auswahl ausgeführt (weit über 150 KB Zeilen werden eingezogen) und anschließend die Verknüpfungen ausgeführt. Wo als 2005 bis R2 es die Auswahl macht und auf dem Remote-Server beitritt. Der Sicherheitskontext für beide Szenarien ist der gleiche.
RateControl
3

+1 beim Versuch, Ihren Abfragekommentar vom Datagod umzuschreiben.

Ich frage mich auch, ob Sie auf der Seite des Verbindungsservers auf ein Berechtigungsproblem stoßen, das zu dieser Verlangsamung führt. Ich habe vor einiger Zeit über diese Verlangsamung des Verbindungsservers gebloggt. Möglicherweise lohnt es sich, die Dauerwellen zu überprüfen (handelt es sich um einen SQL-Verbindungsserver? Oder um ein anderes DBMS? Wenn letzteres der Fall ist, erhalten Sie ohnehin keine hervorragenden Statistiken).

Haben Sie SQL Server 2005 in der Testumgebung noch, um diese Abfrage anzuprobieren und die Umgebung auszuschließen?

Haben Sie die Statistiken seit dem Upgrade neu erstellt?

Mike Walsh
quelle
3

Es gibt so viele Probleme mit diesem Vergleich ... Ich weiß nur nicht, wo ich anfangen soll.

  1. Holen Sie sich die genauen Spezifikationen für Ihre Produktions- und Testmaschinen.

  2. Bestimmen Sie die Netzwerkverbindungen zwischen den verschiedenen verbundenen Servern in beiden Umgebungen. Sind sie gleich schnell? Befinden sich die Server in beiden Umgebungen nebeneinander?

  3. Gibt es überhaupt eine Möglichkeit, die Abfrage neu zu schreiben, um KEINE Verbindungsserver zu verwenden? Wenn Sie Tabellen über mehrere Server hinweg verbinden, sind Sie anfällig für Topologieänderungen und in den meisten Fällen fürchterlich langsam.

  4. Die Verwendung von NOT und OR führt normalerweise zu vollständigen Tabellenscans. Versuchen Sie, die Abfrage neu zu schreiben.

Datagod
quelle