Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Principais respostas para 5 perguntas importantes sobre a função COALESCE no SQL Server


Quão legal é a função COALESCE no SQL?

É legal o suficiente para ser tão importante para mim. E ficarei mais do que feliz em contratar um cara novo que não tenha o mau hábito de ignorar o objetivo da COALESCE. Isso inclui outras expressões e funções para lidar com situações semelhantes.

Hoje, você encontrará as respostas para as cinco perguntas mais frequentes sobre a expressão SQL COALESCE. Um deles está sendo debatido repetidamente.

Começaremos?

Qual ​​é o uso da função COALESCE no SQL?


Ela pode ser respondida em 2 palavras:tratando nulos .

Nulo é um vazio de valores. Em outras palavras, desconhecido. É diferente de uma string vazia ou um número zero. A manipulação de valores nulos requer o uso de expressões e funções. Uma delas é a COALESCE.

Para entender o que quero dizer, veja as afirmações abaixo:
DECLARE @number INT

SELECT @number + 33587

Vai rodar bem? Será.

Existe um problema? Nenhum, no momento.

Mas as instruções resultarão em NULL porque adicionar nulo a um número é igual a NULL.

Se todas as suas consultas atingirem apenas esse nível, você pode parar de ler. Mas é claro que eles não são. Estamos sendo pagos por mais do que produzir esse tipo de código.

Agora, vamos adicionar um pouco de 'desastre':
DECLARE @number INT

SET @number = @number + 33587

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

PRINT 'Success!'

A execução do código acima estará no beco sem saída quando atingir a instrução UPDATE. Ele não imprimirá 'Sucesso!' porque você não pode colocar um nulo em uma coluna não anulável. Essa declaração fala claramente por que precisamos lidar com nulos?

Vamos alterar o código para adicionar uma rede de segurança:
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 mudará o valor nulo para zero e uma soma não será nula.

A lição é que COALESCE é uma das redes de segurança contra nulos. Melhor ainda, manipular nulos corretamente em seu código SQL reduz suas dores de cabeça e permite que você volte para casa mais cedo. Isso é certeza.

Agora você entende porque eu quero na minha equipe alguém diligente em lidar com nulos.

Exemplos mais práticos no uso do SQL COALESCE


Vejamos exemplos mais práticos.

Suponha que você viva em uma região onde algumas pessoas têm nomes do meio, mas outras não. Como você formará o nome completo a partir do primeiro nome, nome do meio e sobrenome sem cair na armadilha do nulo?

Aqui está uma solução possível usando COALESCE:
USE AdventureWorks
GO

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

Outro exemplo:suponha que você seja um funcionário de uma empresa onde o salário bruto é calculado de forma diferente para cada funcionário. Para alguns deles, há taxas horárias. Outros são pagos a taxas semanais ou mensais.

Aqui está um exemplo de tabela junto com uma solução 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;

A tabela contém diferentes modos de pagamento por ID de funcionário. A consulta exige que você forneça um salário mensal para todos.

É aqui que o COALESCE vai brilhar:ele aceita uma lista de valores e pode haver qualquer número de itens. COALESCE escolherá o primeiro que não for nulo:

Legal, não é?

Como o COALESCE funciona no SQL?


A definição de COALESCE é uma expressão que retorna o primeiro valor não nulo de uma lista de valores. A sintaxe COALESCE é:

COALESCE ( expressão [ ,…n ] )

Nosso exemplo anterior com diferentes modos de pagamento de salários ilustra isso.

O que há por baixo do capô


Nos bastidores, a função COALESCE no SQL é uma expressão revestida de açúcar para uma expressão CASE muito mais longa. Elimina a necessidade de digitar um CASE equivalente, que é mais longo (e cansativo, para digitadores preguiçosos como eu). O resultado será o mesmo.

Podemos provar? Sim! Por um lado, a Microsoft admite.

Mas bom para nós, a Microsoft o incluiu no Plano de Execução. Assim, sabemos o que está acontecendo.

Vamos tentar usando um exemplo anterior com salários. Mas antes de executar novamente a consulta abaixo, ative Incluir plano de execução real ou apenas pressione CTRL-M .
SELECT
    employee_id,
    COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Clique no Plano de Execução guia nos resultados. Parece simples, mas nosso tesouro escondido está no Compute Scalar nó. Ao passar o mouse sobre ele, você verá uma expressão chamada Expr1002 (Figura 2). O que poderia ser?

Vamos cavar mais fundo. Clique com o botão direito do mouse e selecione Mostrar XML do plano de execução . Uma nova janela aparecerá. Observe a Figura 3 abaixo:

Aí está a sua declaração CASE. Abaixo está tudo formatado e recuado para facilitar a leitura:
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

Isso é muito longo em comparação com
COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
        )

Foi o que o SQL Server fez com nossa consulta com COALESCE. Tudo é para obter o primeiro valor que não é nulo em uma lista de valores.

Pode ser mais curto?


Eu sei o que você está pensando. Se o SQL Server fizer isso durante o processamento da consulta, COALESCE deve ser lento. Sem mencionar as várias aparições de CONVERT_IMPLICIT. Você prefere usar alternativas?

Por um lado, você mesmo pode digitar uma instrução CASE mais curta. Ou você pode usar ISNULL. Mais sobre isso mais tarde. Falando em ser lento, eu tinha isso coberto antes que este post terminasse.

Quais são as diferenças entre COALESCE e ISNULL no SQL?


Uma das alternativas ao COALESCE é o ISNULL. O uso de COALESCE com 2 valores o torna semelhante a ISNULL. Pelo menos, os resultados parecem semelhantes. Ainda assim, há diferenças notáveis. Você pode usá-lo como um guia para decidir se usará COALESCE ou ISNULL.

(1) ISNULL aceita 2 argumentos. COALESCE aceita uma lista de argumentos


É a diferença mais óbvia. Pela sintaxe, com certeza é diferente.

ISNULL ( check_expression , replace_value )
COALESCE ( expressão [ ,…n ] )


Quando você usa ambos com 2 argumentos, os resultados são os mesmos. As 2 afirmações abaixo resultarão em 1:
SELECT ISNULL(NULL, 1)
SELECT COALESCE(NULL, 1)

Embora os resultados sejam os mesmos, eles têm significados diferentes:
  • ISNULL(NULL, 1) retornou 1 porque o primeiro argumento é NULL.
  • COALESCE(NULL, 1) retornou 1 porque 1 é o primeiro valor não nulo na lista .

(2) COALESCE é o padrão SQL-92


Está certo. Podes verificar. Por exemplo, se você deseja portar seu código SQL para MySQL do SQL Server, COALESCE funcionará da mesma forma. Veja a Figura 4 e compare o resultado da Figura 1:

Usar ISNULL no MySQL, no entanto, acionará um erro se você usar a sintaxe do SQL Server.

por exemplo, execute o seguinte no SQL Server Management Studio e no MySQL Workbench:
SELECT ISNULL(null,1)

O que aconteceu? No SQL Server, a saída é 1. Mas no MySQL, a saída é um erro:

06:36:52 SELECT ISNULL(null,1) Código de erro:1582. Contagem de parâmetro incorreta na chamada para a função nativa 'ISNULL'

O problema é que ISNULL no MySQL aceita 1 argumento e retorna 1 se o argumento for nulo. Caso contrário, retorna 0.

(3) Passar 2 Nulos no COALESCE Aciona um Erro. Tudo bem com ISNULL


Isso acionará um erro:
SELECT COALESCE(NULL, NULL)

O erro é:'Pelo menos um dos argumentos para COALESCE deve ser uma expressão que não seja a constante NULL.'

Isso vai ficar bem:
SELECT ISNULL(NULL, NULL)

Alterar o código COALESCE para algo semelhante abaixo não acionará um erro:
DECLARE @value INT = NULL
SELECT COALESCE(@value,null)

Isso aconteceu porque @value não é uma constante nula.

(4) SQL COALESCE é convertido em CASE. ISNULL permanece ISNULL


Vimos isso em 'Como o COALESCE funciona no SQL?' seção. Aqui, vamos examinar outro exemplo:
SELECT
P.LastName + ', ' + P.FirstName + ' ' + COALESCE(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Inspeção do XML do plano de execução para o operador escalar revela a conversão para 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

Agora, execute uma consulta equivalente usando ISNULL:
SELECT
P.LastName + ', ' + P.FirstName + ' ' + ISNULL(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Em seguida, inspecione o XML do plano de execução para o 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 ainda é ISNULL.

(5) O tipo de dados da expressão resultante é diferente


A determinação do tipo de dados da expressão resultante também é diferente entre COALESCE e ISNULL:
  • ISNULL usa o tipo de dados do primeiro parâmetro.
  • COALESCE retorna o tipo de dados do valor com a precedência mais alta.

Para obter uma lista de precedência de tipo de dados, confira este link.

Vamos a um exemplo:
SELECT
 employee_id
,COALESCE(CAST(weekly_rate * 4 AS MONEY),0.0000) AS monthly_rate
FROM EmployeeWages

Em seguida, inspecione a conversão para CASE no Execution Plan XML :
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

Na expressão CASE acima, o tipo de dado do resultado será numérico(19,4).

Por quê? Tem precedência mais alta do que dinheiro e dinheiro pequeno mesmo se você CAST para dinheiro . Por que numérico e não dinheiro ? Por causa da constante 0,0000.

Caso você esteja se perguntando o que é @1, o XML do Plano de Execução tem a resposta. É o número constante 4.
<ParameterList>
 <ColumnReference Column="@1" ParameterDataType="int" ParameterCompiledValue="(4)"  
       ParameterRuntimeValue="(4)" />
</ParameterList>

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

Novamente, procure o Operador Escalar 's ScalarString :
ISNULL(CONVERT(MONEY,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]*($4.0000),0),($0.0000))

Por fim, o tipo de dados da expressão resultante será dinheiro . É o tipo de dados do primeiro argumento.

Como superar a precedência de dados


Você pode 'superar' a precedência de dados adicionando algumas alterações ao seu código. Anteriormente, o resultado tinha um numérico tipo de dados. Se você quiser que o resultado seja um dinheiro tipo de dados e se livrar do CONVERT_IMPLICIT, faça o seguinte:
SELECT
 employee_id
,COALESCE(CAST(weekly_rate AS MONEY) * ($4.0000),($0.0000)) AS monthly_rate
FROM EmployeeWages

Você notou as constantes ($ 4.000) e ($ 0.0000)? Isso é dinheiro constantes. O que acontece a seguir aparece no XML do plano de execução 's ScalarString :
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

Isso é muito melhor. É mais curto e o CONVERT_IMPLICIT desapareceu. E o tipo de dados resultante é dinheiro .

(6) A nulidade da expressão resultante é diferente


ISNULL(NULL, 1) e COALESCE(NULL, 1) têm resultados semelhantes, mas seus valores de nulidade são diferentes. COALESCE é anulável. ISNULL não é. Você pode ver isso ao usá-lo em colunas computadas.

Vamos nos referir a um exemplo. A instrução abaixo acionará um erro porque a PRIMARY KEY não pode aceitar valores NULL. Ao mesmo tempo, a nulidade da expressão COALESCE para column2 avalia como NULL.
CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0) PRIMARY KEY,  
  column3 AS ISNULL(column1, 0)  
);

Essa instrução é bem-sucedida porque a nulidade da função ISNULL avalia AS NOT NULL.
CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0),  
  column3 AS ISNULL(column1, 0) PRIMARY KEY  
);

(7) O argumento esquerdo de ISNULL é avaliado uma vez. É o oposto com COALESCE


Considere o exemplo anterior novamente:
SELECT
    employee_id,
    COALESCE(
        hourly_rate*22.00*8.00,
        weekly_rate*4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Em seguida, inspecione a ScalarString por esta:
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

Quando a função COALESCE em SQL é convertida para um CASE, cada expressão é avaliada duas vezes (exceto a última). Como você pode ver acima, hourly_rate*22,00*8,00 apareceu duas vezes. Mesma coisa com weekly_rate*4.00 . A última expressão, monthly_rate , apareceu uma vez.

Como o COALESCE avaliará as expressões duas vezes, pode haver uma penalidade de desempenho. Mais sobre isso mais tarde.

No entanto, confira o equivalente ISNULL:
SELECT
 employee_id,
 ISNULL(hourly_rate * 22.00 * 8.00,ISNULL(weekly_rate * 4.00,monthly_rate)) AS  
                                                       monthly_salary
FROM EmployeeWages

Em seguida, inspecionamos a ScalarString no XML do Plano de Execução :
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 você pode ver acima, hourly_rate , taxa_semanal e taxa_mensal apareceu apenas uma vez. Portanto, você não precisa se preocupar com expressões sendo avaliadas duas vezes com ISNULL.

Podemos usar COALESCE em uma cláusula WHERE?


Coisa certa. Não há melhor maneira do que mostrar um exemplo para provar isso.
-- 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 retornará uma string em branco se MiddleName é nulo. Claro, há uma maneira mais curta de produzir o resultado. Mas isso mostra que COALESCE funciona em uma cláusula WHERE.

O que é mais rápido:COALESCE ou ISNULL?


Finalmente, chegamos a um tema quente:Desempenho!

Você terá muitas páginas com testes e comparações, mas haverá uma batalha de defensores da COALESCE e ISNULL nos comentários. Vamos limpar a poeira e a fumaça dessas guerras.

Qual é mais rápido:COALESCE ou ISNULL? Deixe-me começar dizendo que a resposta é:

(bateria rolando)

DEPENDE!

(Queixo caído)

Decepcionado? Vou explicar em um momento.

Primeiro, concordo que ambos parecem ter diferenças de desempenho se você usar o tempo decorrido como sua métrica. Algumas pessoas apoiaram esse fato quando o SQL Server converte as instruções COALESCE para CASE. Enquanto isso, ISNULL permanece como está.

Outros podem raciocinar de forma diferente por causa dos resultados variados. Além disso, para eles, converter COALESCE em CASE é mais rápido do que piscamos os olhos. Assim como o que foi apontado neste tópico, a diferença de desempenho 'é minúscula'. Aqui está outro artigo que dizia que a diferença "é pequena".

No entanto, aqui está um grande negócio:podemos confiar em um minúsculo tempo decorrido como uma métrica? O que realmente importa é a quantidade de leituras lógicas que a consulta tem. É o que vamos apontar em nossos próximos exemplos.

(Confira meu outro artigo sobre leituras lógicas e por que esse fator que atrasa suas consultas.)

Exemplo 1


Vamos examinar o mesmo exemplo e comparar suas leituras lógicas e planos de execução. Antes de executar isso, certifique-se de que STATISTICS IO esteja ATIVADO e Incluir Plano de Execução Real está ativado.
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

Aqui estão os fatos:

As leituras lógicas para ambas as consultas são as mesmas. Ambos são 107 * 8 KB de páginas. Se tivermos um milhão de registros, as leituras lógicas aumentarão, é claro. Mas as leituras lógicas para ambas as consultas serão iguais. Esse é o caso mesmo se COALESCE for convertido em CASE:

Vamos inspecionar o plano de execução. Veja como vamos fazer isso:
  1. Execute a primeira instrução SELECT com a expressão COALESCE.
  2. Clique no Plano de Execução guia nos resultados. Clique com o botão direito do mouse e selecione Salvar plano de execução como . E nomeie o arquivo plan1.sqlplan .
  3. Execute a segunda instrução SELECT com a função ISNULL.
  4. Clique no Plano de Execução guia nos resultados.
  5. Clique com o botão direito do mouse e selecione Comparar plano de exibição .
  6. Selecione o arquivo plan1.sqlplan . Uma nova janela aparecerá.

É assim que vamos inspecionar o plano de execução para todos os exemplos.

Voltando ao nosso primeiro exemplo, veja a Figura 6 para ver a comparação do plano de execução:

Você notou esses pontos importantes na Figura 6?
  • A parte sombreada dos 2 planos (os Index Scans) significa que o SQL Server usou as mesmas operações para as 2 consultas.
  • O QueryPlanHash para os 2 planos é 0x27CEB4CCE12DA5E7, o que significa que o plano é o mesmo para ambos.
  • As poucas diferenças de milissegundos para o tempo decorrido são insignificantes.

Recomendações


É como comparar maçãs com maçãs, mas de tipos diferentes. Uma é uma maçã Fuji do Japão, outra é uma maçã vermelha de Nova York. Ainda assim, ambas são maçãs.

Da mesma forma, o SQL Server requer os mesmos recursos e o plano de execução escolhido para ambas as consultas. A única diferença é o uso de COALESCE ou ISNULL. Pequenas diferenças, pois o resultado final é o mesmo.

Exemplo 2


A grande diferença aparece quando você usa uma subconsulta como argumento para COALESCE e 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)

O código acima terá o mesmo resultado, mas o interior é muito diferente.

Vamos começar com as leituras lógicas:

A instrução SELECT com a expressão COALESCE tem o dobro das leituras lógicas daquela que usou ISNULL.

Mas por que dobrar as leituras lógicas? A comparação do plano de execução revelará ainda mais:

A Figura 8 explica por que as leituras lógicas são duplas usando COALESCE. Veja os 2 nós Stream Aggregate no plano inferior:eles são duplicados. A próxima pergunta é, por que foi duplicado?

Vamos lembrar que o ponto se refere a quando COALESCE é convertido em CASE. Quantas vezes as expressões são avaliadas nos argumentos? DUAS VEZES!

Assim, a subconsulta é avaliada duas vezes. Ele é exibido no plano de execução com nós duplicados.

Isso também explica leituras lógicas duplas usando COALESCE em comparação com ISNULL. Se você planeja examinar o XML do plano de execução da consulta com COALESCE, ele é bastante longo. Mas revela que a subconsulta será executada duas vezes.

O que agora? Podemos enganar isso? É claro! Se você já enfrentou algo assim, o que acredito ser raro, a solução possível é dividir e conquistar. Ou use ISNULL se for apenas uma subconsulta.

Como evitar avaliar a expressão de subconsulta duas vezes


Veja como evitar avaliar a subconsulta duas vezes:
  • Declare uma variável e atribua o resultado da subconsulta a ela.
  • Em seguida, passe a variável como argumento para COALESCE.
  • Repita as mesmas etapas dependendo do número de subconsultas.

Como eu disse, deve ser raro, mas se acontecer, você já sabe o que fazer.

Algumas palavras sobre o nível de isolamento


Avaliar a subconsulta duas vezes pode causar outro problema. Dependendo do nível de isolamento da sua consulta, o resultado da primeira avaliação pode ser diferente da segunda em um ambiente multiusuário. É louco.

Para garantir o retorno dos resultados estáveis, você pode tentar usar um SNAPSHOT ISOLATION. Além disso, você pode usar ISNULL. Ou, pode ser uma abordagem de dividir e conquistar, como apontado acima.

Recomendações


Então, qual é a essência?
  • Sempre verifique as leituras lógicas. Importa mais do que o tempo decorrido. Use o tempo decorrido e tire sua sanidade. Sua máquina e o servidor de produção sempre terão resultados variados. Dê um tempo a si mesmo.
  • Sempre verifique o plano de execução para saber o que está acontecendo nos bastidores.
  • Esteja ciente de que quando COALESCE é traduzido para CASE, as expressões são avaliadas duas vezes. Então, uma subconsulta ou algo semelhante pode ser um problema. Atribuir o resultado da subconsulta a uma variável antes de usá-la no COALESCE pode ser uma solução.
  • O que é mais rápido depende dos resultados das leituras lógicas e dos planos de execução. Não existe uma regra geral para determinar se COALESCE ou ISNULL é mais rápido. Caso contrário, a Microsoft pode informar sobre isso, como fizeram em HierarchyID e SQL Graph.

Eventualmente, isso realmente depende.

Conclusão


Espero que tenha tido uma leitura proveitosa deste artigo. Aqui estão os pontos que discutimos:
  • COALESCE é uma das maneiras de lidar com valores nulos. É uma rede de segurança para evitar erros no código.
  • Ele aceita a lista de argumentos e retorna o primeiro valor não nulo.
  • Ele é convertido em uma expressão CASE durante o processamento da consulta, mas não diminui a velocidade da consulta.
  • Embora existam algumas semelhanças com ISNULL, existem 7 diferenças notáveis.
  • Pode ser usado com a cláusula WHERE.
  • Por fim, não é mais rápido ou mais lento que ISNULL.

Se você gostou deste post, os botões das redes sociais estão esperando pelo seu clique. Compartilhar é se importar.

Obrigada.

Leia também


Manipulando os valores NULL efetivamente com a função SQL COALESCE para iniciantes

Um uso prático da função SQL COALESCE