Utworzyłem funkcję, która akceptuje datę początkową i końcową, przy czym data końcowa jest opcjonalna. Następnie napisałem CASE
w filtrze, aby użyć daty początkowej, jeśli nie minie data końcowa.
CASE WHEN @dateEnd IS NULL
THEN @dateStart
ELSE @dateEnd
END
Kiedy wywołuję funkcję dla ostatniego miesiąca danych:
SELECT * FROM theFunction ('2013-06-01', NULL)
... zapytanie zawiesza się. Jeśli podam datę końcową:
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
... wynik jest zwracany normalnie. Wyjąłem kod z funkcji i uruchomiłem go dobrze w oknie zapytania. Nie mogę też powielić problemu skrzypce. Zapytanie takie jak:
SELECT * FROM theFunction ('2013-04-01', '2013-06-01')
... działa również dobrze.
Czy w zapytaniu (poniżej) jest coś, co może powodować zawieszanie się funkcji po NULL
przekazaniu a dla daty końcowej?
- Plan wykonania dla
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
- Szacowany plan dla
SELECT * FROM theFunction ('2013-06-01', NULL)
sql-server
sql-server-2008-r2
Kermit
źródło
źródło
CASE
sięCOALESCE(@dateEnd,@dateStart)
, czy problem nadal pojawiają?ISNULL()
?SELECT task_state FROM sys.dm_os_tasks WHERE session_id = x
pokazuje? Jeśli spędza dużo czasu pozaRUNNING
stanem, jakie typy oczekiwania czeka ta sesjasys.dm_os_waiting_tasks
?COALESCE
.ISNULL
naprawione.Odpowiedzi:
Część twojego początkowego zapytania jest następująca.
Ta sekcja planu jest pokazana poniżej
Twoje poprawione zapytanie
BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
ma to samo dla tego samego sprzężeniaWydaje się, że różnica polega na tym, że
ISNULL
upraszcza to dalej, w wyniku czego otrzymujesz dokładniejsze statystyki liczności przechodząc do następnego łączenia. Jest to funkcja ceniona w tabeli wbudowanej i wywoływana jest z wartościami dosłownymi, aby mogła zrobić coś takiego.A ponieważ istnieje predykat sprzężenia równań,
b.[Date] = a.d
plan pokazuje również predykat równościb.[Date] = '2013-06-01'
. W rezultacie oszacowanie liczności28,393
wierszy prawdopodobnie będzie dość dokładne.W przypadku wersji
CASE
/,COALESCE
gdy@dateStart
i@dateEnd
są tej samej wartości, upraszcza to OK do tego samego wyrażenia równości i daje ten sam plan, ale kiedy@dateStart = '2013-06-01'
i@dateEnd IS NULL
idzie tylko tak daleko, jakktóre stosuje się również jako dorozumiany wyrok
ColleagueList
. Szacowana liczba wierszy tym razem to79.8
rzędy.Następnym dołączeniem jest
colleagueTime
jest3,249,590
tabelą wierszy, która jest (ponownie) najwyraźniej stertą bez przydatnych indeksów.Ta rozbieżność w szacunkach wpływa na zastosowany wybór łączenia.
ISNULL
Plan wybiera hash dołącz że właśnie przeszukuje tabelę raz.COALESCE
Plan wybiera zagnieżdżone pętle sprzężenia i szacuje się, że będzie ona nadal wystarczy zeskanować tabelę raz i móc szpula wynik i powtórzyć go 78 razy. tj. szacuje, że skorelowane parametry nie zmienią się.Z faktu, że plan zagnieżdżonych pętli nadal działał po dwóch godzinach, założenie o pojedynczym skanie
colleagueTime
wydaje się być wysoce niedokładne.Co do tego, dlaczego szacunkowa liczba wierszy między dwoma złączeniami jest o wiele niższa, nie jestem pewien, nie widząc statystyk w tabelach. Jedynym sposobem, w jaki udało mi się przesunąć szacunkową liczbę wierszy tak dużo w moich testach, było dodanie obciążenia
NULL
wierszy (zmniejszyło to szacunkową liczbę wierszy, chociaż rzeczywista liczba zwróconych wierszy pozostała taka sama).Szacowana liczba wierszy w
COALESCE
planie z moimi danymi testowymi była rzęduLub w SQL
ale to nie odpowiada twojemu komentarzowi, że kolumna nie ma
NULL
wartości.źródło
NULL
wartości dat w żadnej z tych tabel.dbo
nie ma go na liście. Po prostu inne schematy, których nie używam.Wygląda na to, że wystąpił problem z typami danych.
ISNULL
naprawiono problem (dzięki ypercube ). Po kilku badań,COALESCE
jest równoznaczne zCASE
oświadczeniem, że byłem przy użyciu:Paul White wyjaśnia, że:
Aby uniknąć problemów z typem danych, wydaje się, że
ISNULL
jest to odpowiednia funkcja do obsługi tylko dwóch wyrażeń.Fragmenty planu XML
Używając planu XML
CASE
, wyrażenie 2 toNULL
:Używając planu XML
CASE
, wyrażenie 2 jest datą:Używając planu XML
ISNULL
, wyrażenie 2 toNULL
:Używając planu XML
ISNULL
, wyrażenie 2 jest datą:źródło
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
. Typ danych wyrażeń jest nadal taki sam. Oba parametry idate
tak są typem danych. Czy możesz zobaczyć plany wykonania?NULL
.CASE
również nie przyniosło efektu, zapytanie wciąż się zawiesza.ISNULL
spojrzenia Rzut lubią to upraszcza lepiej. Ma prosty predykat równości na[Date]='2013-06-01'
liście ColleagueList, podczas gdyCASE
ten ma predykat na[Date]>='2013-06-01' AND [Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END AND PROBE([Bitmap1067],[Date])
. Szacowane wiersze wychodzące z tego złączenia wynoszą 28 393 dlaISNULL
wersji, ale znacznie niższe79.8
dlaCASE
wersji, co wpływa na wybór łączenia później w planie. Nie jestem pewien, dlaczego miałaby istnieć taka rozbieżność.