Dit is gehasht en opnieuw gehasht. Naast de tip die ik in de opmerking heb genoemd en de links en uitleg die @xQbert hierboven heeft gepost, op verzoek is hier een uitleg van COALESCE vs. ISNULL met behulp van een subquery. Laten we eens kijken naar deze twee zoekopdrachten, die qua resultaten identiek zijn:
SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');
SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');
(Opmerkingen over het gebruik van TOP zonder ORDER BY naar /dev/null/ bedankt.)
In het geval van COALESCE wordt de logica eigenlijk uitgebreid tot zoiets als dit:
SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
THEN (SELECT TOP (1) ...)
ELSE N'foo'
END
Met ISNULL gebeurt dit niet. Er is een interne optimalisatie die ervoor lijkt te zorgen dat de subquery slechts één keer wordt geëvalueerd. Ik weet niet of iemand buiten Microsoft weet hoe deze optimalisatie precies werkt, maar je kunt dit als je de plannen vergelijkt. Hier is het plan voor de COALESCE-versie:
En hier is het plan voor de ISNULL-versie - merk op hoeveel eenvoudiger het is (en dat de scan maar één keer gebeurt):
In het geval van COALESCE gebeurt de scan twee keer. Dit betekent dat de subquery twee keer wordt geëvalueerd, zelfs als deze geen resultaten oplevert. Als u een WHERE-component toevoegt, zodat de subquery 0 rijen oplevert, ziet u een vergelijkbare ongelijkheid - de planvormen kunnen veranderen, maar u ziet nog steeds een dubbele zoekopdracht + opzoeken of scan voor het COALESCE-geval. Hier is een iets ander voorbeeld:
SELECT COALESCE((SELECT TOP (1) name FROM sys.objects
WHERE name = N'no way this exists'), N'foo');
SELECT ISNULL((SELECT TOP (1) name FROM sys.objects
WHERE name = N'no way this exists'), N'foo');
Het plan voor de COALESCE-versie deze keer - je kunt opnieuw de hele vertakking zien die de subquery vertegenwoordigt, letterlijk herhaald:
En weer een veel eenvoudiger plan, dat ongeveer de helft van het werk doet, met ISNULL:
Je kunt deze vraag ook bekijken op dba.se voor wat meer discussie:
Mijn suggestie is dit (en je kunt mijn redenen zien waarom in de tip en de bovenstaande vraag):vertrouwen maar verifiëren. Ik gebruik altijd COALESCE (omdat het de ANSI-standaard is, meer dan twee argumenten ondersteunt en niet zulke gekke dingen doet met de prioriteit van het gegevenstype) tenzij Ik weet dat ik een subquery gebruik als een van de uitdrukkingen (wat ik me niet kan herinneren ooit gedaan te hebben buiten theoretisch werk zoals dit) of ik ervaar een echt prestatieprobleem en wil gewoon vergelijken om te zien of COALESCE vs. ISNULL er een heeft aanzienlijk prestatieverschil (die ik buiten het subquery-geval nog moet vinden). Aangezien ik COALESCE bijna altijd gebruik met argumenten van soortgelijke gegevenstypen, hoef ik zelden andere tests uit te voeren dan terug te kijken naar wat ik er in het verleden over heb gezegd (ik was ook de auteur van het aspfaq-artikel waar xQbert op wees , 7 jaar geleden).