it-swarm.com.de

Warum tritt in SQL Server 2012 ein Abfragefehler mit leerer Ergebnismenge auf?

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

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
31
DavidN

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

Graphical plans

Obwohl Ausführungspläne ganz links ausgeführt werden und iterativ die Methoden Open und GetRow für untergeordnete Iteratoren aufrufen, um Ergebnisse zurückzugeben, enthält SQL Server 2005 und höher eine Optimierung, bei der häufig nur Ausdrücke verwendet werden definiert durch einen Berechnungsskalar mit Auswertung verschoben, bis eine nachfolgende Operation das Ergebnis erfordert :

Compute Scalar operators that appear in Showplans generated by SET STATISTICS XML might not contain the RunTimeInformation element. In graphical Showplans, Actual Rows, Actual Rebinds, and Actual Rewinds might be absent from the Properties window when the Include Actual Execution Plan option is selected in SQL Server Management Studio. When this occurs, it means that although these operators were used in the compiled query plan, their work was performed by other operators in the run-time query plan. Also note that the number of executes in Showplan output generated by SET STATISTICS PROFILE is equivalent to the sum of rebinds and rewinds in Showplans generated by SET STATISTICS XML. From: MSDN Books Online

In diesem Fall wird der Ausdruck Ergebnis Nur benötigt, wenn die Zeile für die Rückkehr zum Client zusammengestellt wird (was Sie sich am grünen Symbol SELECT vorstellen können). Nach dieser Logik würde eine verzögerte Auswertung bedeuten, dass der Ausdruck niemals ausgewertet wird, da keiner der 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 keine Zeile für die Rückgabe an den Client zusammengestellt werden muss.

Es gibt jedoch eine separate Optimierung, bei der einige Ausdrücke als Laufzeitkonstanten identifiziert und daher einmal ausgewertet werden können, bevor die Abfrageausführung beginnt . In diesem Fall finden Sie einen Hinweis darauf, dass dies aufgetreten ist, im showplan XML (Clustered Index Seek Plan links, Table Scan Plan rechts):

Showplan XML

Ich habe mehr über die zugrunde liegenden Mechanismen geschrieben und wie sie die Leistung beeinflussen können in diesem Blog-Beitrag . Mithilfe 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 eine Referenz für konstante Ausdrücke, und beide Abfragen erzeugen die Fehlermeldung. Das XML für die erste Abfrage enthält:

Constant Expression

Weitere Informationen: Skalare, Ausdrücke und Leistung berechnen

39
Paul White 9

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. Schlagen Sie die Werte in der Datentabelle nach, die für die Abfrage benötigt werden

Dieser Pfad wird ausgewählt, da der Primärschlüssel eine where -Klausel enthält. Es kommt nie zum zweiten Schritt, sodass die Abfrage nicht fehlschlägt.

Der zweite hat keinen Primärschlüssel zum Ausführen, daher nähert er 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 ist 1/0 verursacht 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 aus select in den Tabellenscanvorgang. Dies spart häufig Schritte bei der Auswertung der Abfrage.

Diese Optimierung ist jedoch keine uneingeschränkte gute Sache. Tatsächlich scheint es den SQL Server Dokumentation selbst zu verletzen, der besagt, dass die where -Klausel vor dem select ausgewertet wird. Nun, sie könnten eine gelehrte Erklärung dafür haben, was dies bedeutet. Für die meisten Menschen würde die logische Verarbeitung von where vor select (unter anderem) bedeuten, dass "keine select- Klauselfehler in Zeilen generiert werden, die nicht an den Benutzer zurückgegeben werden ".

21
Gordon Linoff