Ich habe eine unterdurchschnittliche Abfrage überprüft, die folgendermaßen aussieht:
WHERE manymany.Active = -1
AND manymany.Check1 = -1
AND manymany.WebsiteID = @P1
AND CURRENT_TIMESTAMP BETWEEN ISNULL(manymany.FromDate, '1950-01-01') AND ISNULL(manymany.UptoDate, '2050-01-01')
AND main.Active = -1
AND main.StatusID = 1
AND CURRENT_TIMESTAMP BETWEEN main.FromDate AND ISNULL(main.UptoDate, '2050-01-01')
AND (main.TextCol1 IS NOT NULL OR main.TextCol2 IS NOT NULL)
ORDER BY aux.SortCode
Ich habe versehentlich den SSMS-Abfrage-Designer für diese Abfrage verwendet und die Abfrage wie folgt neu geschrieben:
WHERE manymany.Active = -1
AND manymany.Check1 = -1
AND manymany.WebsiteID = @P2
AND CURRENT_TIMESTAMP BETWEEN ISNULL(manymany.FromDate, '1950-01-01') AND ISNULL(manymany.UptoDate, '2050-01-01')
AND main.Active = -1
AND main.StatusID = 1
AND CURRENT_TIMESTAMP BETWEEN main.FromDate AND ISNULL(main.UptoDate, '2050-01-01')
AND main.TextCol1 IS NOT NULL
OR manymany.Active = -1
AND manymany.Check1 = -1
AND manymany.WebsiteID = @P2
AND CURRENT_TIMESTAMP BETWEEN ISNULL(manymany.FromDate, '1950-01-01') AND ISNULL(manymany.UptoDate, '2050-01-01')
AND main.Active = -1
AND main.StatusID = 1
AND CURRENT_TIMESTAMP BETWEEN main.FromDate AND ISNULL(main.UptoDate, '2050-01-01')
AND main.TextCol2 IS NOT NULL
ORDER BY aux.SortCode
Wenn Sie genau hinsehen werden Sie feststellen , dass es einfach den erweiterten OR
Zustand durch Wiederholung alle Bedingungen , dh es verändert a AND (b OR c)
zu (a AND b) OR (a AND c)
.
Die resultierende Abfrage war 50% kleiner in Bezug auf die Kosten und 33% kleiner in Bezug auf die Ausführungszeit. Ich verstehe einfach nicht, warum das Neuanordnen der OR
Bedingung den Plan geändert hat, wenn beide Abfragen identisch sind (?). Ich hätte die OR
Bedingung selbst erweitern können, indem ich die Bedingungen kopiert habe, aber warum sollte ich das tun?
Fügen Sie den Plan und den Screenshot ein:
Reihenanzahl:
main 2718
manymany 188761
aux 19
Anmerkungen:
- TextCol1 und TextCol2 sind
text
Datentypen und können nicht indiziert werden - Es gibt Durchschn. 170,20 Datensätze in vielen Tabellen pro Website-ID
IS NOT NULL
... diesen Spalten vomtext
Datentyp sind.main
, (wie viele Datensätze jeder Tabelle enthält) in ähnlicher Weise gelten fürmanymany
undaux
Alias - Tabellen und wie Sie sich ihnen anzuschließen.CREATE TABLE
Anweisungen 9 mit allen Indizes und die vollständige Abfrage hinzu.FROM
Zumindest die Klausel ist wichtig, um zu verstehen, wie der Plan erstellt werden kann.Antworten:
Logischerweise ist es das gleiche und es werden die gleichen Ergebnisse erzielt.
Annahmen
Ich gehe davon aus, dass der Optimierer für den "schnelleren" Plan einige Filteranweisungen oben nicht als mit einigen Filteranweisungen
OR
unten betrachtet. Ich könnte hier völlig außer Kontrolle geraten.Die Gründe für diese Annahmen basieren auf diesem Filterprädikat:
Dieses Filterprädikat verwendet das Ergebnis der Verknüpfung zwischen
Main
Tabelle undmanymany
Tabelle.Beachten Sie, dass EXPR1021 und EXPR1022 in diesem Filter Ausdrücke sind, die vom Skalaroperator in der
manymany
Tabelle erstellt wurden.Dieser Filter besteht aus zwei Teilen, dem ersten mit
(.. AND .. OR .. AND ..)
und dem zweiten einfachenAND
FilterWie Sie sehen können, ist der einzige Unterschied über und unter dem
OR
im ersten Teil dieses FiltersVS
Und der zweite Teil muss wahr sein, egal was passiert, da es sich um
AND
Prädikate ohne irgendwelche handeltOR
.Dies führt zu zusätzlichen Berechnungen der gleichen Funktionen, die meiner Meinung nach nicht benötigt werden. Ich vermute auch hier, dass der Grund, warum SQL Server diese Berechnungen durchführt, darin besteht, dass er nicht weiß, dass sie gleich sind.
Für einige andere Teile der where-Klausel ist bekannt, dass diese identisch sind, z. B. wird in der Haupttabelle die statusid = 1 nur einmal ausgewertet:
In der
manymany
Tabelle wird dieselbe Aussage zweimal ausgewertet:Im 'langsamen' Plan werden die Anweisungen nicht zusammen mit
OR
Klauseln hinzugefügt. Aus diesem Grund generiert der Optimierer einen anderen Plan, indem Filterprädikate separat auf die Tabellen angewendet werden (und keine doppelten Filter).Ende der Annahmen
Vergleich der beiden Pläne
Ich denke, dass Sie mit der Leistung des "schnellen" Plans Glück hatten, aber dass der "schnelle" Plan hässlich werden könnte, wenn die übereinstimmenden Daten zunehmen. Dies kann davon abhängen, wo und wann Sie Ihre Filter anwenden (und von anderen Faktoren) .
Die schnelle Planfilterung
Im 'schnellen' Plan: SQL Server wendet einige der Filter nach dem Verknüpfen der
main
Tabelle mit dermanymany
Tabelle aufgrund unterschiedlicher Kombinationen mit den beiden BlöckenOR
+ (AND ... AND ... AND...
) an. Die Spalten ausmaintable
werden gefiltert, nachdem alle möglichen Kombinationen mit dermanymany
Tabelle gefunden wurden.Infolgedessen wird dasselbe Prädikat zweimal in der
manymany
Tabelle ausgeführt:Für die Prädikate über und unter dem
OR
.Dies ist jedoch bei einigen Suchprädikaten auf dem
main
Tisch nicht der FallDanach erfolgt die Verknüpfung, und ein noch größeres Filterprädikat für die Ergebnisse der Verknüpfung zwischen
main
undmanymany
erfolgt erneut für alle möglichen KombinationenBeachten Sie, dass EXPR1021 und EXPR1022 in diesem Filter Ausdrücke sind, die vom Skalaroperator in der
manymany
Tabelle erstellt wurden.Dieser Filter besteht aus zwei Teilen, dem ersten mit
(.. AND .. OR .. AND ..)
und dem zweiten einfachenAND
FilterWie Sie sehen können, ist der einzige Unterschied über und unter dem
OR
im ersten Teil dieses FiltersVS
Und der zweite Teil muss wahr sein, egal was passiert, da es sich um
AND
Prädikate ohne irgendwelche handeltOR
.Dies führt zu zusätzlichen Berechnungen, die meiner Meinung nach nicht benötigt werden.
Die langsame Planfilterung
Im 'langsamen' Plan: SQL Server wendet den Filter als Ergebnis des
AND (TextCol1 IS NOT NULL OR TextCol2 IS NOT NULL
Teils) direkt auf die Haupttabelle an und verbindet sich dann mit dermanymany
Tabelle, um den Rest herauszufiltern und 15 Zeilen zu erhalten.Main
Tabellenfiltermanymany
TabellenfilterEinige andere, manchmal überlappende Informationen:
Der langsamere Plan
Wenn wir uns den langsameren Plan ansehen, wird der Clustered-Index PK_main in einem Operator für Rechenskalar, Filter und verschachtelte Schleifen verwendet:
Wenn wir dies mit den geschätzten Zeilen vergleichen , die zurückgegeben werden sollen, sehen wir einen Unterschied:
Es werden 93 Zeilen geschätzt, die vom Prädikat beim Scan zurückgegeben werden sollen:
Das ist ungefähr 20x weniger als erwartet, das sind 1947 Zeilen .
Danach der Compute-Skalar oder diese Anweisung:
wird auf diesen 1947 Zeilen ausgewertet.
Dann den Filteroperator (
main.TextCol1 IS NOT NULL OR main.TextCol2 IS NOT NULL
), um ihn auf 1374 Zeilen zu reduzieren.Verbinden Sie danach diese 1374 Zeilen mit der
dbo.manymany
Tabelle, um 15 Zeilen zurückzugeben.Der schnellere Plan
Der schnellere Plan verwendet den NC-Index:
CVR_main_4
onthe dbo.Main
table,Es wird mit einem Suchprädikat gefiltert, wobei 27 Zeilen an den
nested loops
Join-Operator zurückgegeben und erneut mit derdbo.manymany
Tabelle verknüpft werden.Und die tatsächlich zurückgegebenen Zeilen sind noch niedriger als die geschätzten Zeilen :
27 tatsächliche Zeilen für eine Schätzung von 152 Zeilen
Filtern
Ein großer Unterschied besteht darin, wo die Filterung stattfindet und wo dies beim "langsameren" Plan direkt auf dem
dbo.Main
Tisch erfolgt:Mit dem Prädikat:
TextCol1 IS NOT NULL OR TextCol2 IS NOT NULL
Und wendet diesen Filter auf 1943 Zeilen an.
Die andere Filterung erfolgt direkt auf dem
dbo.manymany
Tisch(suchen) Prädikate auf
dbo.manymany
Während der andere
OR
nach dem 'schnelleren' Plan nach dem Join vondbo.Main
bis gefiltertdbo.manymany
wird und in den 27 Zeilen zu einem viel größeren Filter führt.Viel größerer Filter mit mehreren
OR
in 27 Zeilen.Ein weiterer Unterschied ist der Key Lookup Operator:
Dies erhält 10 zusätzliche Spalten aus dem Clustered-Index, muss dies jedoch nur für 27 Zeilen tun.
Ein weiterer Grund, warum der Optimierer den "langsameren" Plan wählt, könnte sein, dass der Optimierer der Meinung ist, dass es besser wäre, die anderen Spalten nicht nachzuschlagen.
Ist der schnelle Plan noch schneller oder wird er immer "schneller" sein?
Ich denke, wenn die Daten, die durch den Filter fließen, zunehmen, ist der "langsame" Plan besser. Nicht nur aufgrund der Schlüsselsuche, sondern auch aufgrund des größeren Filteroperators weiter unten im Plan.
In diesem Fall neben der Indizierung. Sie können die Filterung verbessern, indem Sie die Abfrage mithilfe einer
UNION
Anweisung in mehrere Teile aufteilen.Wie so:
quelle
a AND (b OR c)
=(a AND b) OR (a AND c)
?a AND (b OR c)
es ähnelt der langsamen Abfrage, bei derb
oderc
direkt in der Haupttabelle gefiltert wird, um sich dann mita
(ManyMany) zu verbinden, um die zu erhalten verbleibende Ergebnisse.(a and b) or (a and c)
filtert nach dem Join der beiden Tabellen, um diese nach Erhalt der Ergebnismenge des Joins herauszufiltern, weila
undc
kann nur zusammen mita
und gefiltert werdenb
.1*1
und1+1
ist für SQL nicht gleich. Dies ist am Ende Computer- und Maschinensprache. Wenn es klug genug wird, warum werden Datenbankadministratoren benötigt?!?Bei der ersten Abfrage muss mit einem Scan begonnen werden, während bei der zweiten Abfrage der nicht gruppierte Index für eine Suche verwendet werden konnte.
Stellen Sie sich vor, Sie haben 100 Murmeln in einer Tüte und möchten sie prüfen, um nur diejenigen auszuwählen, die blau und weiß oder blau und rot sind.
Die erste Abfrage lautet: Schauen Sie sich die 100 Murmeln an und wählen Sie das gesamte Blau aus. Wenn Sie das getan haben, überprüfen Sie alle und sehen Sie, ob es welche mit Weiß oder Rot gibt.
Die zweite Frage lautet: Geh in die Tasche und nimm nur blaue und weiße oder blaue und rote Murmeln.
Die zweite Abfrage wäre schneller, da Sie nicht zuerst jeden Marmor auf das Blau untersuchen müssten. Sie können diesen Schritt mit dem kombinieren, was Sie wirklich wollten: Blau und Weiß oder Blau und Rot.
So sehe ich es sowieso. Letztendlich erforderte die erste Abfrage einen Tabellenscan und die zweite verwendete die Suche von Anfang an. Es musste noch eine Schlüsselsuche und ein Scan durchgeführt werden, da der nicht gruppierte Index nicht über alle erforderlichen Informationen verfügte. Zu diesem Zeitpunkt musste jedoch ein viel kleinerer Datensatz durchsucht werden, sodass er schneller war.
quelle
Plan Link funktioniert nicht.
Sie haben unvollständige Informationen angegeben. Es ist wichtig, die Tabellenverknüpfungsspalte und ihren Datentyp zu kennen.
WAS ist
aux.SortCode
? WAS istaux
Alias? Wo ist es in Query?Es gibt weitere Möglichkeiten, die Abfrage neu anzuordnen.
In diesem Fall,
SQL Optimizer
Cardianility Estimate
ist sehr schlecht.Dieselbe Bedingung mit zu wiederholen
OR
ist eine schlechte Idee.Sie können
many
Tabellendatensatz in#Temp
Tabelle oder setzenCTE
Dann endlich
manymany
mit#Temp
Tisch verbinden.Wenn Sie
#Temp
mehr als 100/200index
Datensätze haben, können Sie in der Spalte erstellen, die sich mit vielen verbinden.quelle