Това е хеширано и повторно хеширано. В допълнение към съветът, който посочих в коментара и връзките и обяснението @xQbert, публикувано по-горе, по заявка тук е обяснение на COALESCE срещу ISNULL с помощта на подзаявка. Нека разгледаме тези две заявки, които по отношение на резултатите са идентични:
SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');
SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');
(Коментари относно използването на TOP без ORDER BY към /dev/null/ благодаря.)
В случая COALESCE логиката всъщност се разширява до нещо подобно:
SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
THEN (SELECT TOP (1) ...)
ELSE N'foo'
END
С ISNULL това не се случва. Има вътрешна оптимизация, която изглежда гарантира, че подзаявката се оценява само веднъж. Не знам дали някой извън Microsoft е запознат с това как точно работи тази оптимизация, но можете да го направите, ако сравните плановете. Ето плана за версията COALESCE:
И ето плана за ISNULL версията - забележете колко по-опростен е (и че сканирането се случва само веднъж):
В случая COALESCE сканирането се извършва два пъти. Това означава, че подзаявката се оценява два пъти, дори и да не дава никакви резултати. Ако добавите клауза WHERE, така че подзаявката да дава 0 реда, ще видите подобно несъответствие - формите на плана може да се променят, но пак ще видите двойно търсене+търсене или сканиране за случая COALESCE. Ето един малко по-различен пример:
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');
Планът за версията COALESCE този път - отново можете да видите целия клон, който представлява подзаявката, повторена дословно:
И отново много по-опростен план, който върши приблизително половината работа, използвайки ISNULL:
Можете също да видите този въпрос на dba.se за още дискусия:
Моето предложение е следното (и можете да видите причините защо в съвета и горния въпрос):доверявайте се, но проверявайте. Винаги използвам COALESCE (защото е стандарт ANSI, поддържа повече от два аргумента и не прави толкова странни неща с приоритет на типа данни) освен ако Знам, че използвам подзаявка като един от изразите (което не си спомням да съм правил извън теоретична работа като тази) или изпитвам реален проблем с производителността и просто искам да сравня, за да видя дали COALESCE срещу ISNULL има някакви значителна разлика в производителността (която извън случая на подзаявка, все още трябва да открия). Тъй като почти винаги използвам COALESCE с аргументи от подобни типове данни, рядко ми се налага да правя каквото и да е тестване, освен да поглеждам назад към това, което съм казал за него в миналото (също така бях автор на статията за aspfaq, която xQbert посочи , преди 7 години).