2009-02-06 9 views
14

Ok, ich verstehe, dass dies eine ziemlich vage Frage ist, aber ertragen Sie mit mir.Warum wählt ein SQL-Join einen nicht optimalen Abfrageplan?

Ich habe dieses Problem bei verschiedenen Gelegenheiten mit verschiedenen und nicht verwandten Abfragen erlebt. Die Abfrage dauert unter vielen Minuten auszuführen:

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT JOIN (SELECT <Fields> FROM <Multiple Tables Joined>) ON <Condition> 

jedoch nur durch das Hinzufügen der Hinweis verbinden sie die ausführt, in nur wenigen Sekunden abfragen:

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT HASH JOIN (SELECT <Fields> FROM <Multiple Tables Joined>) ON <Condition> 

Das Merkwürdige ist, die Art der in der angegebenen JOIN Hinweis ist nicht wirklich was die Leistung verbessert. Scheinbar verursacht der Hinweis, dass der Optimierer die Unterabfrage isoliert ausführt und dann beitritt. Ich sehe die gleiche Leistungsverbesserung, wenn ich eine Tabellenwertfunktion (keine Inline-Funktion) für die Unterabfrage erzeuge. z.B.

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT JOIN dbo.MySubQueryFunction() ON <Condition> 

Jeder hat irgendwelche Ideen, warum der Optimierer in diesem Fall so dumm ist?

+0

Welche Version von SQL Server verwenden Sie? – Austin

+0

Ich habe das Problem in beiden 2005 und 2008 –

Antwort

13

Wenn eine dieser Tabellen Tabellenvariablen sind, verwendet der Optimierer eine schlechte Schätzung von 0 Zeilen und wählt normalerweise eine verschachtelte Schleife als Join-Methode.

Dies geschieht aufgrund fehlender Statistiken zu den beteiligten Tabellen.

+0

Ich verwende keine Tabellenvariablen, aber es gibt oft Ansichten in der Unterabfrage. Ihre Argumentation macht jedoch Sinn für mich. –

+1

Wenn ich den Verknüpfungshinweis lösche, ändert sich der Abfrageplan erheblich und es werden verschachtelte Schleifen eingeführt. Ich kann nicht finden, wo es die schlechte Schätzung der Reihen macht, aber ich kann nicht mehr Zeit verbringen, um zu schauen. –

7

Optimierer ist ein Algorithmus. Es ist nicht dumm oder schlau, es funktioniert so, wie es programmiert ist.

Hash join bedeutet, dass eine Hash-Tabelle in einer kleineren Zeilenquelle erstellt wird. Aus diesem Grund muss die innere Abfrage zuerst ausgeführt werden.

Im ersten Fall könnte der Optimierer eine nested loop gewählt haben. Sie hat die Join-Bedingung in die innere Abfrage verschoben und die innere Abfrage bei jeder Iteration mit einem zusätzlichen Prädikat ausgeführt. Möglicherweise findet es keinen geeigneten Index für dieses Prädikat, und bei jeder Iteration fand ein full table scan statt.

Es ist schwer zu sagen, warum dies passiert, es sei denn, Sie buchen Ihre genaue Abfrage und wie viele Zeilen in Ihren Tabellen sind.

Mit einer Tabellenfunktion ist es unmöglich, eine Join-Bedingung in die innere Abfrage zu schieben, deshalb wird sie nur einmal ausgeführt.

+0

Ich stimme zu, dass das scheint zu geschehen. Ich weiß nur nicht, warum der Optimierer eine verschachtelte Schleife ausführt. –

+0

Es ist schwer zu sagen, wir müssen genaue Abfrage sehen und wie viele Zeilen in den Tabellen sind. – Quassnoi

+0

Ich habe versucht, die Abfrage zu reduzieren, aber die kleinste, die ich bekomme, während das Problem noch reproduziert wird, ist 43 Zeilen.Ich möchte nicht den Schmerz durchmachen, wenn ich versuche, das ohne die Datenbank zu analysieren. –

-4

In SQL Server 2005: T-SQL-Abfrage beantwortet diese und viele andere Fragen. Einer der besten Looks unter der Haube von T-SQL Datenabruf und Verb-Verarbeitung, die ich je gesehen habe. (Nein, ich bin kein Autor des Buches, noch bin ich irgendeinem Autor oder Autoren des Buches oder Microsoft oder Microsoft Press angegliedert. Dies ist einfach eine unglaubliche Arbeit, und verschiedene DBAs habe ich in die Vergangenheit gedreht paar Jahre stimmen zu.)

+0

Ich kenne Itzik - er ist wahrscheinlich einer der klügsten SQL-Leute auf dem Planeten. – keithwarren7

Verwandte Themen