[MSSQL] CASE strasznie wydłuża zapytanie - jak poprawić?

0

Cześć, mam takie zapytanie:

select fi.ID, (case when fi.st = 1 then max(ev2.date) 
	else max(ev.date) end) as lastOut 
from tabela1 fi
left join tabela2 ed on ed.fiID = fi.ID
left join tabela3 ev on ev.eID = fi.eID and
		dbo.get_date(ev.date) = dbo.get_date(ed.endDate) and
		ev.deleted = 0 and (ev.isOut = 1 or ev.isOut is null)
left join tabela3 ev2 on ev2.eID = fi.eID and
		ev2.date <= ed.endDate and
		ev2.deleted = 0 and (ev2.isOut = 1 or ev2.isOut is null)
group by fi.id, fi.scheduleType
order by fi.ID	    

Jak widać joinuję 2 razy jedną tabelę, ale z różnymi warunkami.
W zależności of pola w tabeli FI odpowiednio liczę lastOut.

Niestety to zapytanie zajmuje mi ponad 20 sekund, gdzie bez case'a zajmuje sekundę, może kilka.
Czemu tak się wydłużyło i jak mógłbym to zoptymalizować?

[dopisane]
OK, udało mi się dodać po jednym warunku do złączeń i trwa teraz 3 sekundy. Jednak, jeśli ktoś widzi jeszcze jakąś opcję optymalizacji, to bym prosił o jakieś wskazówki :)

0

Co mowi execution plan?

0
johny_bravo napisał(a)

Co mowi execution plan?

http://rapidshare.com/files/245900982/juhas.sqlplan.html

Mówi, że sort zajmuje 77%. W prawdzie nie umiem za bardzo czytać planów, ale po usunięciu ORDER BY czas wykonania wcale nie był krótszy.

0

Strasznie duzo wynikow dostajesz w tym zapytaniu - 91 tys., byc moze dlatego sortowanie jest najciezsze. Po drugie case musi sie wykonac dla wszystkich tych wartosci, co tez nie jest bez znaczenia. Co jest najbardziej obciazajaca operacja po usunieciu sorta?

0

Plan bez sorta wygląda następująco:

http://rapidshare.com/files/247692725/juhas.sqlplan.html

Najwięcej(66%) Hash Match(Aggregate)

0

To ciagle jest ponad 100 tys. wynikow. Czemu taka ilosc jednym selectem? Przeciez i tak nie obrobisz tego po stronie klienta. Ten Hash Match jest wlasnie dla dopasowania case'a czyli fi.scheduleType = 1. Dla takiej ilosci wierszy to dopasowanie nie ma prawa byc szybkie ;)

Sprobuj ograniczyc ilosc wierszy, ktore beda dopasowywane casem.

0
johny_bravo napisał(a)

Sprobuj ograniczyc ilosc wierszy, ktore beda dopasowywane casem.

Hmmm, no właśnie nie za bardzo mogę, bo potrzebuję je wszystkie. To zapytanie to część większego działania po stronie serwera :)

0

To podziel to zapytanie na 2, jedno z where x = 1 i drugie where x <> 1. Sprawdz jak sie wtedy zachowa. Czy na scheduleType jest index? Jaka jest roznorodnosc wartosci scheduleType?

0

ScheduleType to liczba z zakresu 0..3
Trudno stwierdzić, jaka jest różnorodność, a na tabeli, w której to pole jest jest clustered_index(jak na każdej innej).

0

W takim wypadku prawdopodobnie i tak nie skorzystasz z indeksu, zbyt mala selektywnosc kolumny. Sprawdzales wariant z where?

0
johny_bravo napisał(a)

Sprawdzales wariant z where?

Jeszcze nie. Ale nie rozumiem za bardzo, mam po prostu wpisać: "where x = 1", czy za to x podstawić coś konkretnego? ;>

0

Ekhem... x, czyli fi.st = 1... Nie chcialo mi sie tego przepisywac. Skoro to czesc wiekszego zapytania, to fi.st stanowi de facto czesc wiekszego warunku. Sprobuj wiec zapytanie zapisac za pomoca 2 zapytan, gdzie w jednym bedzie fi.st = 1 a w drugim fi.st <> 1. Where powinien byc potraktowany troche lepiej niz case.

0
johny_bravo napisał(a)

Ekhem... x, czyli fi.st = 1... Nie chcialo mi sie tego przepisywac. Skoro to czesc wiekszego zapytania, to fi.st stanowi de facto czesc wiekszego warunku. Sprobuj wiec zapytanie zapisac za pomoca 2 zapytan, gdzie w jednym bedzie fi.st = 1 a w drugim fi.st <> 1. Where powinien byc potraktowany troche lepiej niz case.

Tak, faktycznie jest dużo lepiej. Teraz mam 1 sekundę zamiast 4 :)
THX!

0

To mnie cieszy :)

Jak chcesz jeszcze docisnac to podeslij kolejne plany wykonania ;) Moze sie da.

0
johny_bravo napisał(a)

To mnie cieszy :)

Jak chcesz jeszcze docisnac to podeslij kolejne plany wykonania ;) Moze sie da.

No, dzisiaj przerobiłem jakąś 1/4 bazy i wraz z Twoją wskazówką dostałem czas mniejszy o jakieś 10 - 15 sekund na całej operacji. Wiem, że można jeszcze szybciej ;)

Tak więc kolejna porada by się przydała tu: http://4programmers.net/Forum/viewtopic.php?id=145767 :D

Podejrzewam, że select zawsze będzie szybszy od kursora.
A to sprawdzenie jest wykonywane wiele, wiele razy :)

0

dosyc czesto przerabialem ten problem w pracy i okazuje sie ze dla duzej ilosci danych case jest wolniejszy niz where + union all.

Sprobuj moze podzielic case na osobne select'y z uwzglednieniem warunku z case i je union all.

SELECT a, b , CASE WHEN c = 1 THEN c + 20 ELSE c END
from Tab
where warunek

przerabialem na

SELCT a, b, c+20
from Tab
WHERE warunek 
            AND c = 1
UNION ALL
SELECT a,b,c
from Tab
WHERE c <> 1

index na c (zwykly nie klastrowy)

1 użytkowników online, w tym zalogowanych: 0, gości: 1