Ich habe eine etwas komplexe SQL Server 2008-Abfrage (ungefähr 200 Zeilen ziemlich dichtes SQL), die nicht so ausgeführt wurde, wie ich es brauchte. Im Laufe der Zeit sank die Leistung von etwa 0,5 Sekunden auf etwa 2 Sekunden.
Beim Blick auf den Ausführungsplan war es ziemlich offensichtlich, dass durch die Neuordnung der Verknüpfungen die Leistung verbessert werden konnte. Ich tat es und es tat es ... bis zu ungefähr 0,3 Sekunden. Jetzt hat die Abfrage den Hinweis "OPTION FORCE ORDER" und das Leben ist gut.
Heute komme ich und räume die Datenbank auf. Ich archiviere ungefähr 20% der Zeilen und ergreife keine Aktion in der relevanten Datenbank, außer das Löschen von Zeilen ... der Ausführungsplan wird VOLLSTÄNDIG abgespritzt . Es wird völlig falsch eingeschätzt, wie viele Zeilen bestimmte Teilbäume zurückgeben, und (zum Beispiel) ersetzt a:
<Hash>
mit
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Jetzt steigt die Abfragezeit von ungefähr 0,3 s auf ungefähr 18 s. (!) Nur weil ich Zeilen gelöscht habe. Wenn ich den Abfragehinweis entferne, habe ich wieder eine Abfragezeit von ca. 2 Sekunden. Besser, aber schlechter.
Ich habe das Problem nach dem Wiederherstellen der Datenbank an mehreren Standorten und Servern reproduziert. Das einfache Löschen von etwa 20% der Zeilen aus jeder Tabelle verursacht immer dieses Problem.
- Ist dies normal für eine erzwungene Verknüpfungsreihenfolge, um die Abfrageschätzungen vollständig ungenau zu machen (und damit die Abfragezeiten unvorhersehbar zu machen)?
- Sollte ich nur damit rechnen, dass ich entweder eine nicht optimale Abfrageleistung akzeptieren oder sie wie ein Falke beobachten und Abfragehinweise häufig manuell bearbeiten muss? Oder vielleicht auch jeden Join andeuten? .3s bis 2s ist ein großer Erfolg.
- Ist es offensichtlich, warum der Optimierer nach dem Löschen von Zeilen explodierte? Beispiel: "Ja, es wurde ein Beispielscan durchgeführt. Da ich die meisten Zeilen früher im Datenverlauf archiviert habe, hat das Beispiel nur spärliche Ergebnisse geliefert, sodass die Notwendigkeit einer sortierten Hash-Operation unterschätzt wurde."
Wenn Sie Ausführungspläne sehen möchten, schlagen Sie bitte einen Ort vor, an dem ich sie veröffentlichen kann. Ansonsten habe ich das atemberaubendste Stück probiert. Hier ist die grundlegende Fehleinschätzung: Zahlen in Parens sind (geschätzte: tatsächliche) Zeilen.
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Beachten Sie, dass die innere Schleife voraussichtlich 908 Zeilen scannt, stattdessen jedoch 52.258.441. Wenn es genau gewesen wäre, hätte dieser Zweig ungefähr 2 ms statt 12 Sekunden gelaufen. Vor dem Löschen der Zeilen war diese Schätzung der inneren Verknüpfung nur um den Gesamtfaktor 2 verschoben und wurde als Hash-Übereinstimmung für zwei gruppierte Indizes durchgeführt.