Warum ändern sich die SQL Server-Zeilenschätzungen, wenn ich einen Verknüpfungshinweis hinzufüge?

15

Ich habe eine Abfrage, die ein paar Tabellen verknüpft und ziemlich schlechte Ergebnisse erzielt - Zeilenschätzungen sind weit entfernt (1000-mal), und der Join mit verschachtelten Schleifen wird ausgewählt, was zu mehreren Tabellensuchen führt. Die Form der Abfrage ist recht einfach und sieht ungefähr so ​​aus:

SELECT t1.id
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
LEFT OUTER JOIN t4 ON t3.t4_id = t4.id 
WHERE t4.id = some_GUID

Als ich mit der Abfrage herumspielte, stellte ich fest, dass sie um ein Vielfaches schneller ausgeführt wird, wenn ich sie anspreche, einen Merge-Join für einen der Joins zu verwenden. Dies kann ich verstehen - Zusammenführen ist eine bessere Option für die Daten, die zusammengeführt werden, aber SQL Server schätzt es einfach nicht richtig, wenn die verschachtelten Schleifen ausgewählt werden.

Was ich nicht vollständig verstehe, ist, warum dieser Verknüpfungshinweis alle Schätzungen für alle Planoperatoren ändert? Beim Lesen verschiedener Artikel und Bücher bin ich davon ausgegangen, dass die Kardinalitätsschätzungen durchgeführt werden, bevor der Plan erstellt wird. Wenn Sie also einen Hinweis verwenden, werden die Schätzungen nicht geändert, sondern SQL Server wird ausdrücklich angewiesen, eine bestimmte physische Join-Implementierung zu verwenden.

Was ich jedoch sehe, ist, dass der Merge-Hinweis dazu führt, dass alle Schätzungen so ziemlich perfekt werden. Warum passiert dies und gibt es übliche Techniken, mit denen das Abfrageoptimierungsprogramm eine bessere Schätzung ohne einen Hinweis vornehmen kann - wenn man bedenkt, dass Statistiken dies offensichtlich zulassen?

UPD: anonymisierte Ausführungspläne finden Sie hier: https://www.dropbox.com/s/hchfuru35qqj89s/merge_join.sqlplan?dl=0 https://www.dropbox.com/s/38sjtv0t7vjjfdp/no_hints_join.sqlplan?dl = 0

Ich habe die von beiden Abfragen verwendeten Statistiken mit TF 3604, 9292 und 9204 überprüft, und diese sind identisch. Gescannte / gesuchte Indizes unterscheiden sich jedoch zwischen den Abfragen.

Außerdem habe ich versucht, die Abfrage mit OPTION (FORCE ORDER)auszuführen - sie läuft sogar noch schneller als der Merge-Join und wählt für jeden Join HASH MATCH.

Alexander Shelemin
quelle
3
Haben Sie bemerkt, dass Sie eine äußere Verknüpfung haben, aber Sie verwenden dann die Tabelle in der where-Klausel?
James Z
@JamesZ - ja, mir ist das bewusst, ich glaube aber nicht, dass es ein Problem damit gibt.
Alexander Shelemin
9
@AlexSh Nun, es gibt ein logisches / semantisches Problem damit, denn das ändert Ihre äußere Verknüpfung in eine innere Verknüpfung.
Aaron Bertrand

Antworten:

21

Beim Lesen verschiedener Artikel und Bücher bin ich davon ausgegangen, dass die Kardinalitätsschätzungen durchgeführt werden, bevor der Plan erstellt wird.

Nicht genau. Eine anfängliche Kardinalitätsschätzung wird abgeleitet (nach Vereinfachungen und anderen Arbeiten), die die vom Optimierer gewählte anfängliche Verknüpfungsreihenfolge beeinflusst.

Nachfolgende Untersuchungen (während der kostenbasierten Optimierung) können jedoch häufig dazu führen, dass neue Kardinalitätsschätzungen berechnet werden. Diese späteren CEs können mehr oder weniger genau sein. Wenn sich eine Unterschätzung ergibt, wählt das Optimierungsprogramm möglicherweise einen Plan, der billiger aussieht, aber tatsächlich viel länger ausgeführt wird.

Im Allgemeinen gibt es keine Garantie dafür, dass Kardinalitätsschätzungen für semantisch identische Teilbäume zu denselben Ergebnissen führen. Immerhin handelt es sich um einen statistischen Prozess, und einige Vorgänge werden von CE besser unterstützt als andere.

In Ihrem Fall scheint es einen anderen Faktor zu geben: Der Optimierer führt einen Top ein (oder verschiebt ihn), wodurch ein Zeilenziel für den untergeordneten Baum festgelegt wird:

Fragment planen

Wenn Sie das Ablaufverfolgungsflag 4138 (auf 2008 R2 oder höher) aktivieren, stimmen die Schätzungen möglicherweise besser mit den Erwartungen überein, oder sogar, dass das Optimierungsprogramm keine verschachtelten Schleifen mehr auswählt.

Was ich jedoch sehe, ist, dass der Merge-Hinweis dazu führt, dass alle Schätzungen so ziemlich perfekt werden.

Hier steckt ein bisschen Glück. Die Leute neigen dazu, Abfragen oder zumindest die Verknüpfungen in der Reihenfolge zu schreiben, in der sie erwarten, dass sie physisch ausgeführt werden. Die Verwendung eines Verknüpfungshinweises wird mit einem impliziten Hinweis geliefert FORCE ORDER, der die Verknüpfungsreihenfolge an die Textform anpasst und viele Optimierungserkundungsregeln deaktiviert, die zu einer erneuten Schätzung der Kardinalität führen können.

Außerdem habe ich versucht, die Abfrage mit OPTION (FORCE ORDER)auszuführen - sie läuft sogar noch schneller als der Merge-Join und wählt für jeden Join HASH MATCH.

Dies entspricht dem Hinweis auf einen Join, schränkt jedoch die Auswahl des physischen Join-Operators nicht ein. Auch hier ist es sehr wahrscheinlich, dass Sie einen vernünftigen Plan erhalten, wenn Sie die Reihenfolge der Abfrageverknüpfungen logisch geschrieben haben. Natürlich lassen Sie auf diese Weise einen Großteil der Fähigkeiten des Optimierers aus, was in allgemeineren Situationen möglicherweise nicht zu optimalen Ergebnissen führt.

Sie werden es wahrscheinlich nicht FORCE ORDERsehr oft verwenden wollen, da es sich um einen äußerst mächtigen Hinweis (Direktive) handelt, der umfassendere Auswirkungen hat, als nur die Reihenfolge der Verknüpfungen zu erzwingen. Dies verhindert beispielsweise, dass das Optimierungsprogramm Aggregate verschiebt und Teilaggregationen einführt. Ich rate sehr davon ab, diesen Hinweis zu verwenden, außer in Ausnahmefällen und von wirklich erfahrenen Tunern.

Eine detaillierte Analyse würde mehr Zeit als bisher erfordern und Zugriff auf eine reine Statistikkopie der Datenbank.

Paul White Monica wieder einsetzen
quelle
-10

Das Wo negiert das Linke
Warum es dem Optimierer schwer machen?
Bei 3 oder mehr schließt sich der Optimierer Defensive gehen TEND und in Schleife schließt sich wie Speicher schützt
ein oder Zustand in der Verknüpfung wird es auch in einer Schleife gehen neigen kommen - muss ich harte Beweise haben es jedes Mal geschehen - nein - immer noch eine Realität
Mit mehreren verbindet Pull Bedingungen aus dem , wo in der Verbindung , wenn Sie können

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
  JOIN t4 
        ON t3.t4_id = t4.id 
       AND t4.id = some_GUID 

Oder noch besser - ich wette, das wird deine Hinweise oder deine Kraft treffen oder übertreffen

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
       AND t3.t4_id = some_GUID

Das Problem mit Hinweisen ist, dass sie sich auf Daten in einem bestimmten Zustand beziehen. Schreiben Sie eine saubere Abfrage und lassen Sie den Optimierer seine Arbeit erledigen. Manchmal braucht es einfach mehr Statistiken, um das Richtige zu tun, aber dann wird es sich festsetzen.

Warum unterschiedliche Schätzungen. Ein anderer Plan. Beginnen Sie mit Abfragen, die dem Optimierer eine Kampfchance geben.

Paparazzo
quelle