sql >> Base de Datos >  >> RDS >> Sqlserver

Uso correcto de IsNULL y Coalesce

Esto ha sido hash y re-hash. Además de el consejo que señalé en el comentario y los enlaces y la explicación que @xQbert publicó anteriormente, a pedido aquí hay una explicación de COALESCE vs. ISNULL usando una subconsulta. Consideremos estas dos consultas, que en términos de resultados son idénticas:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');

(Comentarios sobre el uso de TOP sin ORDER BY para /dev/null/ gracias.)

En el caso COALESCE, la lógica en realidad se expande a algo como esto:

SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
    THEN (SELECT TOP (1) ...)
    ELSE N'foo'
END

Con ISNULL, esto no sucede. Hay una optimización interna que parece garantizar que la subconsulta solo se evalúe una vez. No sé si alguien fuera de Microsoft sabe exactamente cómo funciona esta optimización, pero puede hacerlo si compara los planes. Aquí está el plan para la versión COALESCE:

Y aquí está el plan para la versión ISNULL:observe cuánto más simple es (y que el escaneo solo ocurre una vez):

En el caso COALESCE, el escaneo ocurre dos veces. Lo que significa que la subconsulta se evalúa dos veces, incluso si no arroja ningún resultado. Si agrega una cláusula WHERE de modo que la subconsulta produzca 0 filas, verá una disparidad similar:las formas del plan pueden cambiar, pero aún verá una búsqueda doble + búsqueda o exploración para el caso COALESCE. Aquí hay un ejemplo ligeramente diferente:

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');

Esta vez, el plan para la versión COALESCE:de nuevo, puede ver la rama completa que representa la subconsulta repetida textualmente:

Y nuevamente un plan mucho más simple, haciendo aproximadamente la mitad del trabajo, usando ISNULL:

También puede ver esta pregunta en dba.se para más discusión:

Mi sugerencia es esta (y puede ver mis razones en el consejo y en la pregunta anterior):confíe pero verifique. Siempre uso COALESCE (porque es el estándar ANSI, admite más de dos argumentos y no hace cosas tan complicadas con la precedencia del tipo de datos) a menos que Sé que estoy usando una subconsulta como una de las expresiones (que no recuerdo haber hecho nunca fuera de un trabajo teórico como este) o estoy experimentando un problema de rendimiento real y solo quiero comparar para ver si COALESCE vs. ISNULL tiene algún diferencia sustancial de rendimiento (que fuera del caso de la subconsulta, todavía tengo que encontrar). Dado que casi siempre uso COALESCE con argumentos de tipos de datos similares, rara vez tengo que hacer alguna prueba que no sea revisar lo que dije al respecto en el pasado (también fui el autor de el artículo aspfaq que señaló xQbert , hace 7 años).