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

Principales respuestas a 5 preguntas candentes sobre la función COALESCE en SQL Server

¿Qué tan genial es la función COALESCE en SQL?

Es lo suficientemente genial como para ser tan importante para mí. Y estaré más que feliz de contratar a una persona nueva que no tenga la mala costumbre de ignorar el objetivo de COALESCE. Eso incluye otras expresiones y funciones para manejar situaciones similares.

Hoy encontrará las respuestas a las cinco preguntas más frecuentes sobre la expresión SQL COALESCE. Uno de estos se está debatiendo una y otra vez.

¿Empezamos?

¿Cuál es el uso de la función COALESCE en SQL?

Se puede responder en 2 palabras:manejo de nulos .

Nulo es un vacío de valores. En otras palabras, desconocido. Es diferente de una cadena vacía o un número cero. El manejo de valores nulos requiere el uso de expresiones y funciones. Uno de ellos es COALESCE.

Para entender lo que quiero decir, vea las siguientes declaraciones:

DECLARE @number INT

SELECT @number + 33587

¿Funcionará bien? Lo hará.

¿Hay algún problema? Ninguno, por el momento.

Pero las declaraciones darán como resultado NULL porque agregar nulo a un número es igual a NULL.

Si todas sus consultas solo caen en este nivel, puede dejar de leer. Pero, por supuesto, no lo son. Nos pagan por algo más que producir este tipo de código.

Ahora, agreguemos un poco de 'desastre':

DECLARE @number INT

SET @number = @number + 33587

UPDATE myTable
set col1 = @number   -- Surprise! col1 is NOT NULLABLE
where ID = 1

PRINT 'Success!'

La ejecución del código anterior estará en el callejón sin salida cuando llegue a la instrucción UPDATE. No imprimirá '¡Éxito!' porque no puede poner un valor nulo en una columna que no acepta valores NULL. ¿Esta declaración dice claramente por qué necesitamos manejar valores nulos?

Cambiemos el código para agregar una red de seguridad:

DECLARE @number INT

SET @number = COALESCE(@number,0) + 33587     -- our safety net. Thanks to COALESCE.

UPDATE myTable
set col1 = @number               -- Disaster averted!
where ID = 1

PRINT 'Success!'

COALESCE cambiará el valor nulo a cero, y una suma no será nula.

La lección es que COALESCE es una de las redes de seguridad contra los nulos. Aún mejor, el manejo adecuado de valores nulos en su código SQL reduce sus dolores de cabeza y le permite irse a casa temprano. Eso es seguro.

Ahora entiendes por qué quiero en mi equipo a alguien diligente en el manejo de nulos.

Más Ejemplos Prácticos en el Uso de SQL COALESCE

Vamos a referirnos a ejemplos más prácticos.

Suponga que vive en una región donde algunas personas tienen segundos nombres, pero otras no. ¿Cómo formará el nombre completo a partir del primer nombre, el segundo nombre y el apellido sin caer en la trampa nula?

Aquí hay una posible solución usando COALESCE:

USE AdventureWorks
GO

SELECT
p.LastName + ', ' + p.FirstName + ' ' + COALESCE(p.MiddleName + ' ','') AS FullName
FROM Person.Person p

Otro ejemplo:suponga que es un empleado de una empresa donde el salario bruto se calcula de manera diferente para cada empleado. Para algunos de ellos, hay tarifas por hora. A otros se les paga a tarifas semanales o mensuales.

Aquí hay una muestra de tabla junto con una solución de consulta usando COALESCE:

-- STEP 1: Create the table
CREATE TABLE EmployeeWages (
    employee_id INT PRIMARY KEY,
    hourly_rate SMALLMONEY,
    weekly_rate SMALLMONEY,
    monthly_rate MONEY,
    CHECK(
        hourly_rate IS NOT NULL OR
        weekly_rate IS NOT NULL OR
        monthly_rate IS NOT NULL)
);

-- STEP 2: Insert data
INSERT INTO
    EmployeeWages(
        employee_id,
        hourly_rate,
        weekly_rate,
        monthly_rate
    )
VALUES
    (1,60, NULL,NULL),
    (2,40, NULL,NULL),
    (3,NULL, 1000,NULL),
    (4,NULL, NULL,7000),
    (5,NULL, NULL,5000);

-- STEP 3: Query the monthly salary.
SELECT
    employee_id,
    COALESCE(
        hourly_rate*22.00*8.00,
        weekly_rate*4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

La tabla contiene diferentes modos de pago por ID de empleado. La consulta requiere que generes un salario mensual para todos.

Aquí es donde brillará COALESCE:acepta una lista de valores, y puede haber cualquier cantidad de elementos. COALESCE elegirá el primero que no sea nulo:

Genial, ¿no?

¿Cómo funciona COALESCE en SQL?

La definición de COALESCE es una expresión que devuelve el primer valor no nulo de una lista de valores. La sintaxis COALESCE es:

COALESCE ( expresión [ ,…n ] )

Nuestro ejemplo anterior con diferentes modos de pago de salarios ilustra esto.

Qué hay debajo del capó

Debajo del capó, la función COALESCE en SQL es una expresión recubierta de azúcar para una expresión CASE mucho más larga. Elimina la necesidad de escribir un CASO equivalente, que es más largo (y agotador, para mecanógrafos perezosos como yo). El resultado será el mismo.

¿Podemos demostrarlo? ¡Sí! Por un lado, Microsoft lo admite.

Pero bien por nosotros, Microsoft lo incluyó en el Plan de Ejecución. Por lo tanto, sabemos lo que está pasando.

Intentémoslo usando un ejemplo anterior con salarios. Pero antes de volver a ejecutar la consulta a continuación, active Incluir plan de ejecución real o simplemente presione CTRL-M .

SELECT
    employee_id,
    COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Haga clic en Plan de ejecución pestaña en los resultados. Parece simple, pero nuestra joya escondida se encuentra en Compute Scalar nodo. Cuando pasa el mouse sobre él, ve una expresión llamada Expr1002 (Figura 2). ¿Qué podría ser?

Profundicemos. Haga clic con el botón derecho y seleccione Mostrar plan de ejecución XML. . Una ventana nueva aparecerá. Eche un vistazo a la Figura 3 a continuación:

Ahí está su declaración CASE. A continuación se muestra todo formateado y sangrado para facilitar la lectura:

CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                            *(22.00)*(8.00) IS NOT NULL
     THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                       [TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)*(22.00)*(8.00),0)
     ELSE CASE WHEN    
          CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)
                                            *(4.00) IS NOT NULL
          THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),                                                         
                       [TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),0)
          ELSE CONVERT_IMPLICIT(numeric(23,8),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0)
          END
END

Eso es bastante largo en comparación con

COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
        )

Eso es lo que hizo SQL Server con nuestra consulta con COALESCE. Todo es para obtener el primer valor que no es nulo en una lista de valores.

¿Puede ser más corto?

Sé lo que estás pensando. Si SQL Server hace eso durante el procesamiento de consultas, COALESCE debe ser lento. Sin mencionar las múltiples apariciones de CONVERT_IMPLICIT. ¿Preferirías usar alternativas?

Por un lado, puede escribir una instrucción CASE más corta usted mismo. O bien, puede utilizar ISNULL. Más sobre eso más adelante. Hablando de ser lento, lo tenía cubierto antes de que termine esta publicación.

¿Cuáles son las diferencias entre COALESCE e ISNULL en SQL?

Una de las alternativas a COALESCE es ISNULL. Usar COALESCE con 2 valores lo hace similar a ISNULL. Al menos, los resultados parecen similares. Aún así, hay diferencias notables. Puede usarlo como guía para decidir si usará COALESCE o ISNULL.

(1) ISNULL Acepta 2 Argumentos. COALESCE acepta una lista de argumentos

Es la diferencia más obvia. Por la sintaxis, es seguro que es diferente.

ISNULL ( expresión_verificación , valor_reemplazo )
COALESCE ( expresión [ ,…n ] )

Cuando usa ambos con 2 argumentos, los resultados son los mismos. Las 2 afirmaciones a continuación darán como resultado 1:

SELECT ISNULL(NULL, 1)
SELECT COALESCE(NULL, 1)

Aunque los resultados son los mismos, tienen un significado diferente:

  • ISNULL(NULL, 1) devolvió 1 porque el primer argumento es NULL.
  • COALESCE(NULL, 1) devolvió 1 porque 1 es el primer valor no nulo de la lista .

(2) COALESCE es el estándar SQL-92

Así es. Usted puede comprobarlo. Por ejemplo, si desea portar su código SQL a MySQL desde SQL Server, COALESCE funcionará de la misma manera. Consulte la Figura 4 y compare el resultado de la Figura 1:

Sin embargo, usar ISNULL en MySQL generará un error si usa la sintaxis de SQL Server.

por ejemplo, ejecute lo siguiente en SQL Server Management Studio y MySQL Workbench:

SELECT ISNULL(null,1)

¿Qué sucedió? En SQL Server, la salida es 1. Pero en MySQL, la salida es un error:

06:36:52 SELECT ISNULL(null,1) Código de error:1582. Conteo de parámetros incorrecto en la llamada a la función nativa 'ISNULL'

La cuestión es que ISNULL en MySQL acepta 1 argumento y devuelve 1 si el argumento es nulo. De lo contrario, devuelve 0.

(3) Pasar 2 nulos en COALESCE desencadena un error. Está bien con ISNULL

Esto activará un error:

SELECT COALESCE(NULL, NULL)

El error es:"Al menos uno de los argumentos para COALESCE debe ser una expresión que no sea la constante NULL".

Esto estará bien:

SELECT ISNULL(NULL, NULL)

Cambiar el código COALESCE a algo similar a continuación no generará un error:

DECLARE @value INT = NULL
SELECT COALESCE(@value,null)

Eso sucedió porque @value no es una constante nula.

(4) SQL COALESCE se convierte a CASE. ISNULL permanece ISNULL

Hemos visto esto en ‘¿Cómo funciona COALESCE en SQL?’ sección. Aquí, examinemos otro ejemplo:

SELECT
P.LastName + ', ' + P.FirstName + ' ' + COALESCE(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Inspección del XML del Plan de Ejecución para el operador escalar revela la conversión a CASE:

 [AdventureWorks].[Person].[Person].[LastName] as [p].[LastName]+N', '
+[AdventureWorks].[Person].[Person].[FirstName] as [p].[FirstName]+N' '
+CASE WHEN ([AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' ') IS NOT NULL
      THEN [AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' '
      ELSE N''
 END

Ahora, ejecuta una consulta equivalente usando ISNULL:

SELECT
P.LastName + ', ' + P.FirstName + ' ' + ISNULL(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Luego, inspeccione el XML del plan de ejecución para el operador escalar:

 [AdventureWorks].[Person].[Person].[LastName] as [p].[LastName]+N', '
+[AdventureWorks].[Person].[Person].[FirstName] as [p].[FirstName]+N' '
+isnull([AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' ',N'')

ISNULL sigue siendo ISNULL.

(5) El tipo de datos de la expresión resultante es diferente

La determinación del tipo de datos de la expresión resultante también es diferente entre COALESCE e ISNULL:

  • ISNULL usa el tipo de datos del primer parámetro.
  • COALESCE devuelve el tipo de datos del valor con la prioridad más alta.

Para obtener una lista de precedencia de tipos de datos, consulte este enlace.

Pongamos un ejemplo:

SELECT
 employee_id
,COALESCE(CAST(weekly_rate * 4 AS MONEY),0.0000) AS monthly_rate
FROM EmployeeWages

Luego, inspeccione la conversión a CASE en el XML del plan de ejecución :

CASE WHEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]
                                           *CONVERT_IMPLICIT(smallmoney,[@1],0),0) IS NOT NULL
     THEN CONVERT_IMPLICIT(numeric(19,4), CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]
                                           *CONVERT_IMPLICIT(smallmoney,[@1],0),0),0)
     ELSE (0.0000)
END

En la expresión CASE anterior, el tipo de datos del resultado será numeric(19,4).

¿Por qué? Tiene mayor precedencia que dinero y dinero pequeño incluso si lo lanzas a dinero . Por qué numérico y no dinero ? Debido a la constante 0.0000.

En caso de que se pregunte qué es @1, el XML del plan de ejecución tiene la respuesta Es el número constante 4.

<ParameterList>
 <ColumnReference Column="@1" ParameterDataType="int" ParameterCompiledValue="(4)"  
       ParameterRuntimeValue="(4)" />
</ParameterList>

Intentémoslo con ISNULL:

SELECT
 employee_id
,ISNULL(CAST(weekly_rate * 4 AS MONEY),0.0000) AS monthly_rate
FROM EmployeeWages

Nuevamente, busque el Operador escalar 's Cadena escalar :

ISNULL(CONVERT(MONEY,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]*($4.0000),0),($0.0000))

Finalmente, el tipo de dato de la expresión resultante será dinero . Es el tipo de datos del primer argumento.

Cómo burlar la precedencia de datos

Puede 'burlar' la precedencia de datos agregando algunos cambios a su código. Anteriormente, el resultado tenía un valor numérico tipo de datos. Si quieres que el resultado sea un dinero tipo de datos y deshacerse de CONVERT_IMPLICIT, haga lo siguiente:

SELECT
 employee_id
,COALESCE(CAST(weekly_rate AS MONEY) * ($4.0000),($0.0000)) AS monthly_rate
FROM EmployeeWages

¿Notaste las constantes ($4.000) y ($0.0000)? Esos son dinero constantes Lo que sucede a continuación aparece en el XML del plan de ejecución. 's Cadena escalar :

CASE WHEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*($4.0000) IS NOT NULL 
     THEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*($4.0000) 
     ELSE ($0.0000) 
END

Eso está mucho mejor. Es más corto y el CONVERT_IMPLICIT se ha ido. Y el tipo de datos resultante es dinero .

(6) La capacidad NULL de la expresión resultante es diferente

ISNULL(NULL, 1) y COALESCE(NULL, 1) tienen resultados similares, pero sus valores de nulabilidad son diferentes. COALESCE es anulable. ISNULL no lo es. Puede ver esto cuando lo usa en columnas calculadas.

Vamos a referirnos a un ejemplo. La siguiente declaración generará un error porque PRIMARY KEY no puede aceptar valores NULL. Al mismo tiempo, la anulabilidad de la expresión COALESCE para column2 evalúa a NULL.

CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0) PRIMARY KEY,  
  column3 AS ISNULL(column1, 0)  
);

Esta instrucción se realiza correctamente porque la nulabilidad de la función ISNULL se evalúa COMO NO NULL.

CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0),  
  column3 AS ISNULL(column1, 0) PRIMARY KEY  
);

(7) El argumento izquierdo de ISNULL se evalúa una vez. Es lo contrario con COALESCE

Considere el ejemplo anterior nuevamente:

SELECT
    employee_id,
    COALESCE(
        hourly_rate*22.00*8.00,
        weekly_rate*4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Luego, inspeccione el ScalarString por esto:

CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                              *(22.00)*(8.00) IS NOT NULL 
     THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                                              [TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                              *(22.00)*(8.00),0) 
     ELSE CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)
                                              *(4.00) IS NOT NULL 
               THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                                        [TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),0) 
               ELSE CONVERT_IMPLICIT(numeric(23,8),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0) 
          END 
END

Cuando la función COALESCE en SQL se convierte a CASE, cada expresión se evalúa dos veces (excepto la última). Como puede ver arriba, tarifa_por_hora*22.00*8.00 apareció dos veces. Lo mismo con weekly_rate*4.00 . La última expresión, monthly_rate , apareció una vez.

Dado que COALESCE evaluará las expresiones dos veces, puede haber una penalización de rendimiento. Más sobre esto más adelante.

Sin embargo, echa un vistazo al equivalente de ISNULL:

SELECT
 employee_id,
 ISNULL(hourly_rate * 22.00 * 8.00,ISNULL(weekly_rate * 4.00,monthly_rate)) AS  
                                                       monthly_salary
FROM EmployeeWages

Luego, inspeccionamos la ScalarString en el Plan de Ejecución XML :

isnull(CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)*(22.00)*(8.00),
       CONVERT_IMPLICIT(numeric(19,8),
isnull(CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),
CONVERT_IMPLICIT(numeric(14,6),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0)),0))

Como puede ver arriba, tarifa_por_hora , tarifa_semanal y tarifa_mensual apareció una sola vez. Por lo tanto, no necesita preocuparse de que las expresiones se evalúen dos veces con ISNULL.

¿Podemos usar COALESCE en una cláusula WHERE?

Cosa segura. No hay mejor manera que mostrar un ejemplo para probar esto.

-- Query all the names in Person table with no middle name

USE AdventureWorks
GO

SELECT
 p.LastName
,p.FirstName
FROM person.Person p
WHERE COALESCE(p.MiddleName,'') = ''

COALESCE devolverá una cadena en blanco si MiddleName es nulo. Por supuesto, hay una forma más corta de producir el resultado. Pero esto muestra que COALESCE funciona en una cláusula WHERE.

¿Qué es más rápido:COALESCE o ISNULL?

Finalmente, hemos llegado a un tema candente:¡Rendimiento!

Obtendrá muchas páginas con pruebas y comparaciones, pero habrá una batalla entre los defensores de COALESCE e ISNULL en los comentarios. Limpiaremos el polvo y el humo de esas guerras.

¿Qué es más rápido:COALESCE o ISNULL? Permítanme comenzar diciendo que la respuesta es:

(redoble de tambores)

¡DEPENDE!

(boquiabierto)

¿Decepcionado? Lo explicaré en un momento.

Primero, estoy de acuerdo en que ambos parecen tener diferencias de rendimiento si usa el tiempo transcurrido como su métrica. Algunas personas apoyaron este hecho cuando SQL Server traduce COALESCE a sentencias CASE. Mientras tanto, ISNULL se queda como está.

Otros pueden razonar de manera diferente debido a los diferentes resultados. Además, para ellos, convertir COALESCE en CASE es más rápido de lo que parpadeamos. Al igual que lo que se señala en este hilo, la diferencia de rendimiento "es minúscula". Estoy de acuerdo. Aquí hay otro artículo que decía que la diferencia "es menor".

Sin embargo, aquí hay un gran problema:¿podemos confiar en un minúsculo tiempo transcurrido como métrica? Lo que realmente importa es cuántas lecturas lógicas tiene la consulta. Es lo que vamos a señalar en nuestros próximos ejemplos.

(Consulte mi otro artículo sobre lecturas lógicas y por qué este factor retrasa sus consultas).

Ejemplo 1

Examinemos el mismo ejemplo y comparemos sus lecturas lógicas y planes de ejecución. Antes de ejecutar esto, asegúrese de que STATISTICS IO esté activado e Incluya el plan de ejecución real está habilitado.

SET STATISTICS IO ON

SELECT
P.LastName + ', ' + P.FirstName + ' ' + COALESCE(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

SELECT
P.LastName + ', ' + P.FirstName + ' ' + ISNULL(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Estos son los hechos:

Las lecturas lógicas para ambas consultas son las mismas. Ambos son 107 * 8KB de páginas. Si tenemos un millón de registros, las lecturas lógicas aumentarán, por supuesto. Pero las lecturas lógicas para ambas consultas serán iguales. Ese es el caso incluso si COALESCE se convierte a CASE:

Inspeccionemos el plan de ejecución. Así es como vamos a hacerlo:

  1. Ejecute la primera instrucción SELECT con la expresión COALESCE.
  2. Haga clic en Plan de ejecución pestaña en los resultados. Haga clic derecho y seleccione Guardar plan de ejecución como . Y nombre el archivo plan1.sqlplan .
  3. Ejecute la segunda instrucción SELECT con la función ISNULL.
  4. Haga clic en Plan de ejecución pestaña en los resultados.
  5. Haz clic derecho y selecciona Comparar plan de presentación .
  6. Seleccione el archivo plan1.sqlplan . Aparecerá una nueva ventana.

Así es como vamos a inspeccionar el plan de ejecución para todos los ejemplos.

Volviendo a nuestro primer ejemplo, vea la Figura 6 para ver la comparación del plan de ejecución:

¿Notaste estos puntos importantes en la Figura 6?

  • La parte sombreada de los 2 planes (los análisis de índice) significa que SQL Server usó las mismas operaciones para las 2 consultas.
  • El QueryPlanHash para los 2 planes es 0x27CEB4CCE12DA5E7, lo que significa que el plan es el mismo para ambos.
  • Las pocas diferencias de milisegundos para el tiempo transcurrido son insignificantes.

Puntos para llevar

Es como comparar manzanas con manzanas, pero de diferentes tipos. Una es una manzana Fuji de Japón, otra es una manzana roja de Nueva York. Aun así, ambas son manzanas.

De manera similar, SQL Server requiere los mismos recursos y el plan de ejecución elegido para ambas consultas. La única diferencia es el uso de COALESCE o ISNULL. Pequeñas diferencias, ya que el resultado final es el mismo.

Ejemplo 2

La gran diferencia aparece cuando usa una subconsulta como argumento tanto para COALESCE como para ISNULL:

USE AdventureWorks
GO

SELECT COALESCE(
       (SELECT
        SUM(th.ActualCost)
        FROM Production.TransactionHistory th
        WHERE th.ProductID = 967)
       ,0) 

SELECT ISNULL(
       (SELECT
        SUM(th.ActualCost)
        FROM Production.TransactionHistory th
        WHERE th.ProductID = 967)
       ,0)

El código anterior tendrá el mismo resultado, pero el interior es muy diferente.

Comencemos con las lecturas lógicas:

La instrucción SELECT con la expresión COALESCE tiene el doble de lecturas lógicas que la que utilizó ISNULL.

Pero, ¿por qué duplicar las lecturas lógicas? La comparación del plan de ejecución revelará aún más:

La Figura 8 explica por qué las lecturas lógicas son dobles usando COALESCE. Vea los 2 nodos de Stream Aggregate en el plano inferior:son duplicados. La siguiente pregunta es, ¿por qué se duplicó?

Recordemos el punto relacionado con cuando COALESCE se convierte en CASE. ¿Cuántas veces se evalúan las expresiones en los argumentos? ¡DOS VECES!

Entonces, la subconsulta se evalúa dos veces. Se muestra en el plan de ejecución con nodos duplicados.

Esto también explica las lecturas lógicas dobles usando COALESCE en comparación con ISNULL. Si planea mirar el XML del plan de ejecución de la consulta con COALESCE, es bastante largo. Pero revela que la subconsulta se ejecutará dos veces.

¿Ahora que? ¿Podemos burlar esto? ¡Por supuesto! Si alguna vez se enfrentó a algo como esto, que creo que es raro, la solución posible es dividir y conquistar. O use ISNULL si es solo una subconsulta.

Cómo evitar evaluar la expresión de subconsulta dos veces

Aquí se explica cómo evitar evaluar la subconsulta dos veces:

  • Declarar una variable y asignarle el resultado de la subconsulta.
  • Luego, pase la variable como argumento a COALESCE.
  • Repita los mismos pasos según el número de subconsultas.

Como dije, debería ser raro, pero si sucede, ya sabes qué hacer.

Algunas palabras sobre el nivel de aislamiento

Evaluar la subconsulta dos veces puede causar otro problema. Según el nivel de aislamiento de su consulta, el resultado de la primera evaluación puede ser diferente al de la segunda en un entorno multiusuario. Es una locura.

Para garantizar que regresen los resultados estables, puede intentar usar un AISLAMIENTO INSTANTÁNEO. Además, puedes usar ISNULL. O bien, puede ser un enfoque de divide y vencerás, como se indicó anteriormente.

Puntos para llevar

Entonces, ¿cuál es la esencia?

  • Siempre verifique las lecturas lógicas. Importa más que el tiempo transcurrido. Usa el tiempo transcurrido y quítate la cordura. Su máquina y el servidor de producción siempre tendrán resultados diferentes. Date un respiro.
  • Revise siempre el plan de ejecución, para saber lo que sucede debajo del capó.
  • Tenga en cuenta que cuando COALESCE se traduce a CASE, las expresiones se evalúan dos veces. Entonces, una subconsulta o algo similar puede ser un problema. Asignar el resultado de la subconsulta a una variable antes de usarla en COALESCE puede ser una solución.
  • Lo que es más rápido depende de los resultados de las lecturas lógicas y los planes de ejecución. No existe una regla general para determinar si COALESCE o ISNULL es más rápido. De lo contrario, Microsoft podría informar sobre eso, como lo hicieron en HierarchyID y SQL Graph.

Eventualmente, realmente depende.

Conclusión

Espero que hayas tenido una lectura valiosa de este artículo. Estos son los puntos que discutimos:

  • COALESCE es una de las formas de manejar valores nulos. Es una red de seguridad para evitar errores en el código.
  • Acepta la lista de argumentos y devuelve el primer valor no nulo.
  • Se convierte en una expresión CASE durante el procesamiento de la consulta, pero no ralentiza la consulta.
  • Si bien hay algunas similitudes con ISNULL, hay 7 diferencias notables.
  • Se puede usar con la cláusula WHERE.
  • Finalmente, no es más rápido ni más lento que ISNULL.

Si te gusta esta publicación, los botones de las redes sociales están esperando tu clic. Compartir es cuidar.

Gracias.

Lea también

Manejo de valores NULL de manera efectiva con la función SQL COALESCE para principiantes

Un uso práctico de la función SQL COALESCE