Ich habe eine Funktion erstellt, die ein Start- und Enddatum akzeptiert, wobei das Enddatum optional ist. Ich habe dann ein CASE
in den Filter geschrieben, um das Startdatum zu verwenden, wenn kein Enddatum überschritten wird.
CASE WHEN @dateEnd IS NULL
THEN @dateStart
ELSE @dateEnd
END
Wenn ich die Funktion für den letzten Monat der Daten aufrufe:
SELECT * FROM theFunction ('2013-06-01', NULL)
... die Abfrage hängt. Wenn ich das Enddatum spezifiziere:
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
... das Ergebnis wird normal zurückgegeben. Ich habe den Code aus der Funktion genommen und ihn in einem Abfragefenster einwandfrei ausgeführt. Ich kann das Problem der Geige auch nicht duplizieren. Eine Abfrage wie:
SELECT * FROM theFunction ('2013-04-01', '2013-06-01')
... funktioniert auch gut.
Gibt es irgendetwas in der Abfrage (unten), das dazu führen könnte, dass die Funktion hängen NULL
bleibt, wenn a für das Enddatum übergeben wird?
- Ausführungsplan für
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
- Geschätzter Plan für
SELECT * FROM theFunction ('2013-06-01', NULL)
sql-server
sql-server-2008-r2
Kermit
quelle
quelle
CASE
mitCOALESCE(@dateEnd,@dateStart)
, scheint das Problem noch?ISNULL()
?SELECT task_state FROM sys.dm_os_tasks WHERE session_id = x
zeigt sich? Wenn es viel Zeit nicht imRUNNING
Zustand verbringt, in welche Wartezeiten kommt diese Sitzungsys.dm_os_waiting_tasks
?COALESCE
.ISNULL
behoben.Antworten:
Ein Teil Ihrer ersten Abfrage lautet wie folgt.
Dieser Abschnitt des Plans ist unten dargestellt
Ihre überarbeitete Abfrage
BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
hat dies für denselben JoinDer Unterschied scheint darin zu liegen, dass er sich
ISNULL
weiter vereinfacht und als Ergebnis genauere Kardinalitätsstatistiken für den nächsten Join erhalten. Dies ist eine Inline-Tabellenwertfunktion, und Sie rufen sie mit Literalwerten auf, damit sie so etwas tun kann.Und da es ein Equi-Join-Prädikat gibt
b.[Date] = a.d
, zeigt der Plan auch ein Gleichheitsprädikatb.[Date] = '2013-06-01'
. Infolgedessen ist die Kardinalitätsschätzung von28,393
Zeilen wahrscheinlich ziemlich genau.Für die
CASE
/COALESCE
-Version, wenn@dateStart
und@dateEnd
derselbe Wert ist, vereinfacht sich OK für denselben Gleichheitsausdruck und gibt denselben Plan an, aber wann@dateStart = '2013-06-01'
und@dateEnd IS NULL
geht nur so weit wiewas es auch als implizites Prädikat gilt
ColleagueList
. Die geschätzte Anzahl der Zeilen beträgt diesmal79.8
Zeilen.Der nächste Join ist
colleagueTime
ist eine3,249,590
Zeilentabelle, die (wieder) anscheinend ein Heap ohne nützliche Indizes ist.Diese Diskrepanz bei den Schätzungen wirkt sich auf die verwendete Verknüpfungsauswahl aus. Der
ISNULL
Plan wählt einen Hash-Join, der die Tabelle nur einmal scannt. DerCOALESCE
Plan wählt einen Join für verschachtelte Schleifen aus und schätzt, dass die Tabelle nur noch einmal gescannt werden muss, um das Ergebnis zu spoolen und 78 Mal wiederzugeben. dh es wird geschätzt, dass sich die korrelierten Parameter nicht ändern werden.Aufgrund der Tatsache, dass der Plan für verschachtelte Schleifen nach zwei Stunden noch lief,
colleagueTime
scheint diese Annahme eines einzelnen Scans gegen sehr ungenau zu sein.Ich bin mir nicht sicher, warum die geschätzte Anzahl der Zeilen zwischen den beiden Verknüpfungen so viel geringer ist, ohne die Statistiken in den Tabellen sehen zu können. Die einzige Möglichkeit, die geschätzten Zeilenzahlen so stark zu verzerren, bestand darin, eine
NULL
Anzahl von Zeilen hinzuzufügen (dies reduzierte die geschätzte Zeilenanzahl, obwohl die tatsächliche Anzahl der zurückgegebenen Zeilen gleich blieb).Die geschätzte Zeilenanzahl im
COALESCE
Plan mit meinen Testdaten lag in der Größenordnung vonOder in SQL
Dies entspricht jedoch nicht Ihrem Kommentar, dass die Spalte keine
NULL
Werte enthält.quelle
NULL
in keiner dieser Tabellen Werte für Datumsangaben.dbo
ist nicht aufgeführt. Nur andere Schemata, die ich nicht benutze.Es scheint, als ob es ein Problem mit den Datentypen gab.
ISNULL
Das Problem wurde behoben (danke ypercube ). Nach einigen RecherchenCOALESCE
entspricht dies derCASE
Aussage, die ich verwendet habe:Paul White erklärt Folgendes:
Um Datentypprobleme zu vermeiden, scheint
ISNULL
es die geeignete Funktion zu sein, nur zwei Ausdrücke zu behandeln.XML-Planauszüge
XML-Plan mit
CASE
Ausdruck 2 lautetNULL
:XML-Plan mit
CASE
, Ausdruck 2 ist ein Datum:XML-Plan mit
ISNULL
Ausdruck 2 lautetNULL
:XML-Plan mit
ISNULL
, Ausdruck 2 ist ein Datum:quelle
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
. Der Ausdrucksdatentyp ist immer noch der gleiche. Und beide Parameter sinddate
sowieso Datentyp. Können Sie die Ausführungspläne anzeigen?NULL
.CASE
ebenfalls keine Auswirkung, die Abfrage bleibt weiterhin hängen.ISNULL
Plan scheint sich besser zu vereinfachen. Es hat ein einfaches Gleichheitsprädikat auf ColleagueList von,[Date]='2013-06-01'
während dasCASE
eine ein Prädikat auf hat[Date]>='2013-06-01' AND [Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END AND PROBE([Bitmap1067],[Date])
. Die geschätzten Zeilen, die aus diesem Join hervorgehen, sind 28.393 für dieISNULL
Version, aber viel niedriger79.8
für dieCASE
Version, die sich später im Plan auf die Join-Auswahl auswirkt. Ich bin mir nicht sicher, warum es eine solche Diskrepanz geben würde.