Kis változtatás, nagy változás

Megint belefutottam egy első ránézésre értelmetlen lassulásra. Nem a várt sebességgel futott egy nem túl bonyolult query, amiben csak pár join, egy nagyon egyszerű szűrés és egy rendezés volt.

Tüzetesebb vizsgálattal viszont már kibújt a lóláb, de szerencsére a javítás nagyon egyszerű volt, így utólag belegondolva. A kérdéses rész így nézett ki:

LEFT JOIN [OrderItem] oi 
    on o.OrderId = oi.OrderId 
        AND ISNULL(oi.Tag, '') <> 'S'

Első olvasatra nem tűnt fel, hogy az ISNULL a problémás. Ha bármilyen funkciót használunk az összekapcsolásnál, akkor az nem tud az indexek mentén működni, hiszen minden egyes sorra ki kell értékelnie a függvény értékét.

Amíg kevés adat volt, addig nem okozott gondot, kiköhögte az eredményt. Amint viszont elért egy kritikus tömeget, már egy percen kívül volt a visszatérési ideje, ezért kódból meghívva timeoutra futott. Megvizsgálva az execution plant egyből láttuk, hogy ez egy index scan és 18 millió rekorddal dolgozik:

clustered index scan

Amint erre ráébredtünk és a homlokunkra csaptunk, a megoldás már egyszerű volt.

LEFT JOIN [OrderItem] oi 
    on o.OrderId = oi.OrderId
WHERE ISNULL(oi.Tag, '') <> 'S'

A joint hagytuk szépen hagy fusson le gyorsan, ahogy csak tud, és a plusz feltételt a szűrés részbe helyeztük át. Az execution plant megvizsgálva is nagy a különbség:

nonclustered index seek

Ugyan egy másik indexet veszi figyelembe, de már seeket használ, és már csak 535 ezer sort használ. Így utólag teljesen egyértelmű, sajnos elvesztünk a nem fontos részletekben, de azért megvolt egy fél óra alatt.