Warum wird in SQL Server 2012 ein Abfragefehler mit leerem Ergebnis angezeigt?

31

Wenn Sie die folgenden Abfragen in MS SQL Server 2012 ausführen, schlägt die zweite Abfrage fehl, jedoch nicht die erste. Außerdem schlagen beide Abfragen fehl, wenn sie ohne die where-Klauseln ausgeführt werden. Ich bin ratlos, warum beide fehlschlagen würden, da beide leere Ergebnismengen haben sollten. Jede Hilfe / Einsicht wird gebeten.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1
DavidN
quelle

Antworten:

39

Ein erster Blick auf die Ausführungspläne zeigt, dass der Ausdruck 1/0in den Compute Scalar-Operatoren definiert ist:

Grafische Pläne

Obwohl Ausführungspläne ganz links ausgeführt werden und iterativ untergeordnete Iteratoren aufgerufen werden Openund GetRowMethoden zum Zurückgeben von Ergebnissen verwendet werden, enthält SQL Server 2005 und höher eine Optimierung, bei der Ausdrücke häufig nur von einem Compute Scalar definiert werden und die Auswertung bis zu einem späteren Zeitpunkt verschoben wird Operation erfordert das Ergebnis :

Compute Scalar-Operatoren, die in von SET STATISTICS XML generierten Showplans angezeigt werden, enthalten möglicherweise nicht das RunTimeInformation-Element.  In grafischen Showplans fehlen möglicherweise die Optionen "Tatsächliche Zeilen", "Tatsächliche Zurückspulen" und "Tatsächliche Zurückspulen" im Eigenschaftenfenster, wenn die Option "Tatsächlichen Ausführungsplan einbeziehen" in SQL Server Management Studio ausgewählt ist.  In diesem Fall bedeutet dies, dass diese Operatoren zwar im kompilierten Abfrageplan verwendet wurden, ihre Arbeit jedoch von anderen Operatoren im Laufzeit-Abfrageplan ausgeführt wurde.  Beachten Sie auch, dass die Anzahl der Ausführungen in der von SET STATISTICS PROFILE generierten Showplan-Ausgabe der Summe der von SET STATISTICS XML generierten Rück- und Zurückspulungen in Showplans entspricht.  Von: MSDN Books Online

In diesem Fall wird der Ausdruck Ergebnis wird nur dann benötigt , wenn die Zeile für die Rückkehr an den Client Montag (die Sie von auftretenden am grünen denken SELECTSymbol). Nach dieser Logik würde eine verzögerte Auswertung bedeuten, dass der Ausdruck niemals ausgewertet wird, da keiner der beiden Pläne eine Rückgabezeile generiert. Um den Punkt ein wenig zu bearbeiten, geben weder der Clustered Index Seek noch der Table Scan eine Zeile zurück, sodass für die Rückgabe an den Client keine Zeile zusammengestellt werden muss.

Es gibt jedoch eine separate Optimierung, bei der einige Ausdrücke als Laufzeitkonstanten identifiziert und so einmalig ausgewertet werden können, bevor die Abfrageausführung beginnt . In diesem Fall kann ein Hinweis darauf im showplan XML gefunden werden (Clustered-Index-Suchplan links, Table-Scan-Plan rechts):

Showplan XML

In diesem Blogbeitrag habe ich mehr über die zugrunde liegenden Mechanismen und deren Auswirkungen auf die Leistung geschrieben . Anhand der dort bereitgestellten Informationen können wir die erste Abfrage so ändern, dass beide Ausdrücke ausgewertet und zwischengespeichert werden, bevor die Ausführung beginnt:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Der erste Plan enthält jetzt auch einen konstanten Ausdrucksverweis, und beide Abfragen erzeugen die Fehlermeldung. Das XML für die erste Abfrage enthält:

Konstanter Ausdruck

Weitere Informationen: Skalare, Ausdrücke und Leistung berechnen

Paul White sagt GoFundMonica
quelle
21

Ich werde intelligent raten (und dabei wahrscheinlich einen SQL Server-Guru anziehen, der eine wirklich detaillierte Antwort geben könnte).

Die erste Abfrage nähert sich der Ausführung wie folgt:

  1. Scannen Sie den Primärschlüsselindex
  2. Suchen Sie die Werte in der Datentabelle, die für die Abfrage benötigt werden

Dieser Pfad wird ausgewählt, weil Sie eine whereKlausel für den Primärschlüssel haben. Der zweite Schritt wird nie erreicht, sodass die Abfrage nicht fehlschlägt.

Der zweite hat keinen Primärschlüssel, auf dem er ausgeführt werden kann, und nähert sich der Abfrage wie folgt:

  1. Führen Sie einen vollständigen Tabellenscan der Daten durch und rufen Sie die erforderlichen Werte ab

Einer dieser Werte 1/0verursacht das Problem.

Dies ist ein Beispiel für die Optimierung der Abfrage durch SQL Server. Zum größten Teil ist dies eine gute Sache. SQL Server verschiebt Bedingungen vom selectin den Tabellen-Scan-Vorgang. Dies erspart häufig Schritte bei der Auswertung der Abfrage.

Diese Optimierung ist jedoch keine uneingeschränkte gute Sache. Tatsächlich scheint es gegen die SQL Server- Dokumentation selbst zu verstoßen, die besagt, dass die whereKlausel vor dem ausgewertet wird select. Nun, sie könnten eine gelehrte Erklärung dafür haben, was dies bedeutet. Für die meisten Menschen, aber logisch Verarbeitung der wherevor dem select(unter anderem) bedeuten würde „erzeugt keine select-Klausel Fehler auf Zeilen nicht an den Benutzer zurückgegeben“.

Gordon Linoff
quelle
1
+1 keine Ahnung, ob Sie Recht haben, aber die beste Antwort, die ich sehen kann, da der einzige Unterschied der Primärschlüssel ist.
1
@GordonLinoff Paul Randal hat soeben über Twitter bestätigt, dass Ihre Antwort voll aufging.
SchmitzIT
4
@Still, die tatsächliche Ausführungsreihenfolge sollte jedoch nicht zu solchen Fehlermeldungen führen.
ypercubeᵀᴹ
7
@ypercube Erland Sommarskog würde mit Ihnen einverstanden sein (Artikel verbinden)
Paul White sagt GoFundMonica
2
Vielen Dank für den Hinweis - Ich habe mich angemeldet und die Anfrage positiv bewertet.
Gordon Linoff