Detta har hashas och återhashats. Förutom tipset jag påpekade i kommentaren och länkarna och förklaringen @xQbert postat ovan, på begäran här är en förklaring av COALESCE vs. ISNULL med hjälp av en underfråga. Låt oss överväga dessa två frågor, som när det gäller resultat är identiska:
SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');
SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');
(Kommentarer om att använda TOP utan ORDER BY till /dev/null/ tack.)
I COALESCE-fallet utökas logiken faktiskt till något sånt här:
SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
THEN (SELECT TOP (1) ...)
ELSE N'foo'
END
Med ISNULL händer inte detta. Det finns en intern optimering som verkar säkerställa att underfrågan bara utvärderas en gång. Jag vet inte om någon utanför Microsoft är insatt i exakt hur denna optimering fungerar, men du kan detta om du jämför planerna. Här är planen för COALESCE-versionen:
Och här är planen för ISNULL-versionen - lägg märke till hur mycket enklare det är (och att skanningen bara sker en gång):
I COALESCE-fallet sker skanningen två gånger. Det betyder att underfrågan utvärderas två gånger, även om den inte ger några resultat. Om du lägger till en WHERE-sats så att underfrågan ger 0 rader, kommer du att se liknande skillnader - planformerna kan ändras, men du kommer fortfarande att se en dubbelsökning+sökning eller scanning efter COALESCE-fallet. Här är ett lite annorlunda exempel:
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');
Planen för COALESCE-versionen denna gång - återigen kan du se hela grenen som representerar underfrågan upprepad ordagrant:
Och återigen en mycket enklare plan, som gör ungefär halva arbetet med ISNULL:
Du kan också se denna fråga på dba.se för mer diskussion:
Mitt förslag är detta (och du kan se mina skäl varför i tipset och ovanstående fråga):lita på men verifiera. Jag använder alltid COALESCE (eftersom det är ANSI-standard, stöder mer än två argument och gör inte lika knasiga saker med datatypsföreträde) om inte Jag vet att jag använder en underfråga som ett av uttrycken (vilket jag inte minns att jag någonsin gjort utanför teoretiskt arbete som detta) eller så upplever jag ett verkligt prestandaproblem och vill bara jämföra för att se om COALESCE vs. ISNULL har någon avsevärd prestandaskillnad (vilket jag inte har hittat utanför subquery-fallet). Eftersom jag nästan alltid använder COALESCE med argument av liknande datatyper, behöver jag sällan göra några andra tester än att titta tillbaka på vad jag har sagt om det tidigare (jag var också författare till aspfaq-artikeln som xQbert påpekade , för 7 år sedan).