SQL Server 2008 R2-Abfrageoptimierungspuzzlespiel
Wir haben zwei Tabellen mit jeweils 9 Millionen Zeilen. 70.000 Zeilen sind unterschiedlich, die anderen sind gleich.
Das ist schnell, 13 Sekunden,
select * from bigtable1
except select * from similar_bigtable2
Dies sortiert die Ausgabe und ist auch schnell, auch 13 Sekunden,
select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column
Das ist zwar enorm langsam:
;with q as (
select * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
Und selbst ein "Trick", den ich manchmal verwende, um SQL Server darauf hinzuweisen, dass er einen bestimmten Teil der Abfrage vorab berechnen muss, funktioniert nicht und führt auch zu langsamen Abfragen:
;with q as (
select top 100 percent * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
In den Abfrageplänen ist der Grund nicht schwer zu finden:
SQL Server platziert zwei Arten von 9 Millionen Zeilen vor dem Hashmatch, während ich es vorziehen würde, nur eine Art von 70.000 Zeilen nach dem Hashmatch hinzuzufügen.
Also die Frage: Wie kann ich das Abfrageoptimierungsprogramm dazu anweisen?
quelle
EXCEPT
(zBOUTER JOIN
) ausprobiert ? Mir ist klar, dass die Syntax weniger praktisch ist, aber Sie können dort möglicherweise besser mit Index- / Verknüpfungshinweisen spielen (oder müssen dies nicht). Die Alternative, die Sie jetzt verwenden (Zeug zuerst in eine #temp-Tabelle), ist eine Umgehung des letzten Auswegs, aber in einigen Fällen ist es die einzige Möglichkeit, das Optimierungsprogramm zu zwingen, zwei Teile einer Abfrage auf die von Ihnen gewünschte Weise vollständig zu trennen.Antworten:
Der Hauptunterschied zwischen diesen beiden Abfrageplänen liegt in der Differenz zwischen Hash Match und Merge Join. Hash Match ist effizienter und wie Sie sehen, wird die Abfrage in Option 1 schneller ausgeführt (ohne CTE).
CTE ist ein großartiges Tool, aber es scheint in zwei Fällen nicht effizient zu sein: Komplexe Prädikate oder nicht eindeutiger Eltern- / Kind-Schlüssel. In Ihrem Fall gibt es keinen eindeutigen Schlüssel und der SQL Server muss die Datensätze zuerst sortieren, um Ihre Anforderung erfüllen zu können. Schauen Sie sich den folgenden Link an, um mehr über dieses Problem zu erfahren : http://blogs.msdn.com/b/sqlcat/archive/2011/04/28/optimize-recursive-cte-query.aspx
Entweder müssen Sie die Langsamkeit akzeptieren oder die Logik mit der WHILE-Schleife neu schreiben, was effizienter sein kann.
quelle
Versuchen Sie das mal, besser?
quelle
Dies ist keine ideale Lösung, aber wenn Sie nicht in der Lage sind, das tsql zu strukturieren, um einen effizienten Plan zu generieren, können Sie einen Planleitfaden festlegen, um den gewünschten Plan zu erzwingen. Dies würde bedeuten, dass wenn ein effizienterer Plan verfügbar wird, SQL dies nicht berücksichtigt, dies jedoch eine Option ist.
quelle