Ich habe ein seltsames Problem bei der Kompilierung von Abfragen, das schwer zu reproduzieren ist. Dies geschieht nur unter hoher Last und kann nicht einfach wiederholt werden.
- Es gibt eine Tabelle T mit den Spalten A, B, C, D.
- Es gibt einen nicht eindeutigen Clustered-Index für T (A, B, C, D).
- Es gibt eine Abfrage SELECT * FROM T WHERE A = @ P1 UND B = @ P2 UND (C = @ P3 ODER C = @ P4) UND D = @ P5. Die Suchbedingung gilt für alle Spalten des Clustered-Index, die 3. Spalte hat ein ODER.
Das Problem ist, dass der Abfrageplan für diese Abfrage nur für A und B das Suchprädikat enthält! Das Prädikat für C und D ist ein gewöhnliches Prädikat. Dies bedeutet, dass der Suchbaum für die Spalten C und D nicht verwendet wird.
Die Datentypen für alle Parameter stimmen mit den Spaltendatentypen überein.
Könnte jemand Hinweise geben, warum dies passieren könnte? SQL-Version ist 2008 R2 (SP1) - 10.50.2789.0 (X64)
OPTION (RECOMPILE)
?Antworten:
Für eine parametrisierte Abfrage Es können nicht nur zwei Suchvorgänge ausgeführt werden
und
Denn wenn
@P3 = @P4
das fälschlicherweise doppelte Zeilen zurückbringen würde. Es würde also einen Operator benötigen, der zuerst Duplikate von diesen entfernt.Nach einem kurzen Test zu diesem Zweck scheint es von der Größe der Tabelle abhängig zu sein, ob Sie diese erhalten oder nicht. Im Test unten
245
/246
Zeilen ist der Grenzpunkt zwischen Plänen (dies war auch der Grenzpunkt zwischen dem Index, der alle auf einer Seite anpasst und 2 Blattseiten und eine Stammseite wird).1 Seiten / 245 Zeilen
Dieser Plan hat eine Suche
A=1 AND B=2
mit einem Restprädikat auf(C=@C1 OR C=@C2) AND D=5
2 Blattseiten / 246 Reihen
Im zweiten Plan sind die zusätzlichen Operatoren dafür verantwortlich, alle Duplikate von den
@C1,@C2
ersten zu entfernen, bevor die Suche (n) durchgeführt werden.Die Suche im zweiten Plan ist tatsächlich eine Bereichssuche zwischen
A=1 AND B=2 AND C > Expr1010
undA=1 AND B=2 AND C < Expr1011
mit einem verbleibenden PrädikatD=5
. Es ist immer noch keine Gleichstellungssuche für alle 4 Spalten. Weitere Informationen zu den zusätzlichen Planbetreibern finden Sie hier .Durch Hinzufügen können
OPTION (RECOMPILE)
die Parameterwerte zur Kompilierungszeit auf Duplikate überprüft werden, und es wird ein Plan mit zwei Gleichheitssuchen erstellt.Das könnte man auch mit erreichen
In diesem Testfall wäre es jedoch wahrscheinlich kontraproduktiv, wenn zwei Suchvorgänge im Index einer einzelnen Seite und nicht einer das logische E / A erhöhen.
quelle
select .. union select ...
würde Ihnen auch zwei Suchanfragen sowie den zusätzlichen Schritt des Entfernens von Duplikaten aus dem Ergebnis geben.SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5
Duplikate, die zurückgegeben werden sollten, konnten jedoch fälschlicherweise entfernt werden. In meinen Beispieldaten, in denen ich alle träge mit dem gleichen Wert bevölkert habe, würde es 1 Zeile nicht zurückgeben256
Stimme voll und ganz Martins Analyse zu. Diese Abfrage kann aufgrund des ODER-Prädikats keine Suche für alle 4 Spalten erzeugen, es sei denn (möglicherweise) mit OPTION (RECOMPILE). Ich vermute, dass dies eine Nadel-im-Heu-Stapel-Abfrage ist, Sie möchten wahrscheinlich nicht den zusätzlichen Aufwand.
Wie wäre es damit:
Ich habe dies nicht getestet, aber der else-Teil sollte 2 Suchvorgänge für alle 4 Werte und eine billige Vereinigung durch Verkettung ergeben. Für den Fall, dass beide Suchvorgänge auf derselben Seite landen, würde ein zusätzliches Lesen der logischen Seite meiner Meinung nach nicht viel Zeit in Anspruch nehmen. Abhängig von Ihren Daten befinden sich die beiden Suchvorgänge jedoch möglicherweise auf unterschiedlichen Seiten.
quelle