Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Le migliori risposte a 5 domande scottanti sulla funzione COALESCE in SQL Server

Quanto è interessante la funzione COALESCE in SQL?

È abbastanza bello essere così importante per me. E sarò più che felice di assumere un nuovo ragazzo che non ha la cattiva abitudine di ignorare l'obiettivo di COALESCE. Ciò include altre espressioni e funzioni per la gestione di situazioni simili.

Oggi troverai le risposte alle cinque domande più frequenti sull'espressione SQL COALESCE. Uno di questi viene discusso più e più volte.

Iniziamo?

Qual ​​è l'uso della funzione COALESCE in SQL?

Si può rispondere in 2 parole:gestione dei null .

Null è un vuoto di valori. In altre parole, sconosciuto. È diverso da una stringa vuota o da un numero zero. La gestione dei valori null richiede l'utilizzo di espressioni e funzioni. Uno di questi è COALESCE.

Per capire cosa intendo, vedere le affermazioni seguenti:

DECLARE @number INT

SELECT @number + 33587

Funzionerà bene? Lo farà.

C'è un problema? Nessuno, al momento.

Ma le istruzioni risulteranno in NULL perché l'aggiunta di null a un numero equivale a NULL.

Se tutte le tue domande rientrano solo a questo livello, puoi interrompere la lettura. Ma ovviamente non lo sono. Veniamo pagati di più rispetto alla produzione di questo tipo di codice.

Ora aggiungiamo un po' di "disastro":

DECLARE @number INT

SET @number = @number + 33587

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

PRINT 'Success!'

L'esecuzione del codice sopra sarà in un vicolo cieco quando raggiunge l'istruzione UPDATE. Non stamperà "Success!" Perché non puoi inserire un null su una colonna non annullabile. Questa affermazione dice chiaramente perché dobbiamo gestire i null?

Cambiamo il codice per aggiungere una rete di sicurezza:

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 cambierà il valore nullo in zero e una somma non sarà nulla.

La lezione è che COALESCE è una delle reti di sicurezza contro i nulli. Ancora meglio, gestire correttamente i null nel tuo codice SQL riduce i tuoi mal di testa e ti consente di tornare a casa presto. Questo è certo.

Ora capisci perché voglio nel mio team qualcuno diligente nella gestione dei null.

Esempi più pratici nell'uso di SQL COALESCE

Facciamo riferimento ad esempi più pratici.

Supponiamo che tu viva in una regione in cui alcune persone hanno un secondo nome, ma altre no. Come formerai il nome completo partendo dal nome, dal secondo nome e dal cognome senza cadere nella trappola del nulla?

Ecco una possibile soluzione utilizzando COALESCE:

USE AdventureWorks
GO

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

Un altro esempio:supponiamo di essere un dipendente di un'azienda in cui la retribuzione lorda è calcolata in modo diverso per ogni dipendente. Per alcuni di loro sono previste tariffe orarie. Altri vengono pagati a tariffe settimanali o mensili.

Ecco un esempio di tabella insieme a una soluzione di query che utilizza 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 tabella contiene diverse modalità di pagamento per ID dipendente. La query richiede di produrre uno stipendio mensile per tutti.

È qui che COALESCE brillerà:accetta un elenco di valori e può esserci un numero qualsiasi di elementi. COALESCE sceglierà il primo che non è nullo:

Pulito, non è vero?

Come funziona COALESCE in SQL?

La definizione di COALESCE è un'espressione che restituisce il primo valore non nullo da un elenco di valori. La sintassi COALESCE è:

COALESCE ( espressione [ ,…n ] )

Il nostro esempio precedente con diverse modalità di pagamento per i salari lo illustra.

Cosa c'è sotto il cofano

Sotto il cofano, la funzione COALESCE in SQL è un'espressione ricoperta di zucchero per un'espressione CASE molto più lunga. Elimina la necessità di digitare un CASE equivalente, che è più lungo (e faticoso, per dattilografi pigri come me). Il risultato sarà lo stesso.

Possiamo dimostrarlo? Sì! Per uno, Microsoft lo ammette.

Ma buon per noi, Microsoft lo ha incluso nel piano di esecuzione. Quindi, sappiamo cosa sta succedendo.

Proviamo usando un esempio precedente con i salari. Ma prima di eseguire nuovamente la query di seguito, attiva Includi piano di esecuzione effettivo oppure premi semplicemente CTRL-M .

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

Fai clic sul Piano di esecuzione scheda nei risultati. Sembra semplice, ma la nostra gemma nascosta si trova nel Compute Scalar nodo. Quando ci passi sopra con il mouse, vedi un'espressione denominata Expr1002 (Figura 2). Cosa potrebbe essere?

Scaviamo più a fondo. Fare clic con il pulsante destro del mouse e selezionare Mostra XML piano di esecuzione . Apparirà una nuova finestra. Dai un'occhiata alla Figura 3 di seguito:

Ecco la tua dichiarazione CASE. Di seguito è riportato il tutto formattato e rientrato per la leggibilità:

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

È piuttosto lungo rispetto a

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

Questo è ciò che ha fatto SQL Server con la nostra query con COALESCE. Tutto serve per ottenere il primo valore che non è nullo in un elenco di valori.

Può essere più breve?

So cosa stai pensando. Se SQL Server esegue questa operazione durante l'elaborazione della query, COALESCE deve essere lento. Per non parlare delle molteplici apparizioni di CONVERT_IMPLICIT. Preferirai usare alternative?

Per uno, puoi digitare tu stesso un'istruzione CASE più breve. Oppure puoi usare ISNULL. Ne parleremo più avanti. A proposito di lentezza, ne ho parlato prima della fine di questo post.

Quali sono le differenze tra COALESCE e ISNULL in SQL?

Una delle alternative a COALESCE è ISNULL. L'uso di COALESCE con 2 valori lo rende simile a ISNULL. Almeno, i risultati sembrano simili. Tuttavia, ci sono differenze notevoli. Puoi usarlo come guida per decidere se utilizzerai COALESCE o ISNULL.

(1) ISNULL Accetta 2 argomenti. COALESCE accetta un elenco di argomenti

È la differenza più evidente. Dalla sintassi, è sicuramente diverso.

ISNULL ( check_expression , replacement_value )
COALESCE ( espressione [ ,…n ] )

Quando si utilizzano entrambi con 2 argomenti, i risultati sono gli stessi. Le 2 affermazioni seguenti risulteranno in 1:

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

Sebbene i risultati siano gli stessi, sono intesi in modo diverso:

  • ISNULL(NULL, 1) ha restituito 1 perché il primo argomento è NULL.
  • COALESCE(NULL, 1) ha restituito 1 perché 1 è il primo valore non nullo nell'elenco .

(2) COALESCE è lo standard SQL-92

Giusto. Puoi verificarlo. Ad esempio, se desideri trasferire il tuo codice SQL su MySQL da SQL Server, COALESCE funzionerà allo stesso modo. Vedere la Figura 4 e confrontare il risultato della Figura 1:

L'utilizzo di ISNULL in MySQL, tuttavia, attiverà un errore se si utilizza la sintassi di SQL Server.

ad esempio, esegui quanto segue in SQL Server Management Studio e MySQL Workbench:

SELECT ISNULL(null,1)

Cosa è successo? In SQL Server, l'output è 1. Ma in MySQL, l'output è un errore:

06:36:52 SELECT ISNULL(null,1) Codice di errore:1582. Conteggio parametri errato nella chiamata alla funzione nativa "ISNULL"

Il fatto è che ISNULL in MySQL accetta 1 argomento e restituisce 1 se l'argomento è nullo. In caso contrario, restituisce 0.

(3) Il superamento di 2 valori nulli in COALESCE provoca un errore. Va bene con ISNULL

Questo attiverà un errore:

SELECT COALESCE(NULL, NULL)

L'errore è:"Almeno uno degli argomenti di COALESCE deve essere un'espressione che non è la costante NULL".

Questo andrà bene:

SELECT ISNULL(NULL, NULL)

La modifica del codice COALESCE in qualcosa di simile di seguito non attiverà un errore:

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

È successo perché @value non è una costante nulla.

(4) SQL COALESCE viene convertito in CASE. ISNULL Soggiorni ISNULL

Lo abbiamo visto in 'Come funziona COALESCE in SQL?' sezione. Qui, esaminiamo un altro esempio:

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

Ispezione del Execution Plan XML per l'operatore scalare rivela la conversione in 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

Ora, esegui una query equivalente usando ISNULL:

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

Quindi, controlla il Execution Plan XML per l'operatore scalare:

 [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 è ancora ISNULL.

(5) Il tipo di dati dell'espressione risultante è diverso

Anche la determinazione del tipo di dati dell'espressione risultante è diversa tra COALESCE e ISNULL:

  • ISNULL utilizza il tipo di dati del primo parametro.
  • COALESCE restituisce il tipo di dati del valore con la precedenza più alta.

Per un elenco della precedenza del tipo di dati, controlla questo link.

Facciamo un esempio:

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

Quindi, controlla la conversione in CASE in 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

Nell'espressione CASE sopra, il tipo di dati del risultato sarà numeric(19,4).

Come mai? Ha una precedenza maggiore rispetto al denaro e piccoli soldi anche se lo trascini in denaro . Perché numerico e non denaro ? A causa della costante 0.0000.

Nel caso ti stia chiedendo cosa sia @1, il Execution Plan XML ha la risposta. È il numero costante 4.

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

Proviamo con ISNULL:

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

Ancora una volta, cerca l'Operatore scalare è Stringa scalare :

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

Infine, il tipo di dati dell'espressione risultante sarà denaro . È il tipo di dati del primo argomento.

Come superare in astuzia la precedenza dei dati

Puoi "superare in astuzia" la precedenza dei dati aggiungendo alcune modifiche al tuo codice. In precedenza, il risultato aveva un numero tipo di dati. Se vuoi che il risultato sia un denaro tipo di dati ed eliminare CONVERT_IMPLICIT, procedere come segue:

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

Hai notato le costanti ($ 4.000) e ($ 0.0000)? Quelli sono denaro costanti. Quello che succede dopo appare nel Execution Plan XML è Stringa scalare :

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

È molto meglio. È più breve e CONVERT_IMPLICIT è sparito. E il tipo di dati risultante è denaro .

(6) La NULLabilità dell'espressione risultante è diversa

ISNULL(NULL, 1) e COALESCE(NULL, 1) hanno risultati simili, ma i loro valori di nullità sono diversi. COALESCE è nullable. ISNULL non lo è. Puoi vederlo quando lo usi su colonne calcolate.

Facciamo un esempio. L'istruzione seguente attiverà un errore perché PRIMARY KEY non può accettare valori NULL. Allo stesso tempo, la capacità di annullare i valori dell'espressione COALESCE per colonna2 restituisce NULL.

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

Questa istruzione ha esito positivo perché il valore Null della funzione ISNULL viene valutato COME NOT NULL.

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

(7) L'argomento di sinistra di ISNULL viene valutato una volta. È l'opposto con COALESCE

Considera di nuovo l'esempio precedente:

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

Quindi, controlla la Stringa scalare per questo:

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 la funzione COALESCE in SQL viene convertita in CASE, ogni espressione viene valutata due volte (tranne l'ultima). Come puoi vedere sopra, tariffa_oraria*22.00*8.00 apparso due volte. Stessa cosa con tariffa_settimanale*4.00 . L'ultima espressione, tariffa_mensile , è apparso una volta.

Poiché COALESCE valuterà le espressioni due volte, può esserci una penalizzazione delle prestazioni. Ne parleremo più avanti.

Tuttavia, controlla l'equivalente ISNULL:

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

Quindi, ispezioniamo la Stringa scalare nel Piano di esecuzione 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))

Come puoi vedere sopra, tariffa_oraria , tariffa_settimanale e tariffa_mensile apparso solo una volta. Quindi, non devi preoccuparti che le espressioni vengano valutate due volte con ISNULL.

Possiamo utilizzare COALESCE in una clausola WHERE?

Cosa certa. Non c'è modo migliore che mostrare un esempio per dimostrarlo.

-- 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 restituirà una stringa vuota se MiddleName è zero. Naturalmente, c'è un modo più breve per produrre il risultato. Ma questo mostra che COALESCE funziona in una clausola WHERE.

Qual ​​è il più veloce:COALESCE o ISNULL?

Infine, siamo arrivati ​​a un argomento caldo:le prestazioni!

Avrai molte pagine con test e confronti, ma ci sarà una battaglia tra i sostenitori di COALESCE e ISNULL nei commenti. Elimineremo la polvere e i fumi di quelle guerre.

Qual è più veloce:COALESCE o ISNULL? Inizio col dire che la risposta è:

(rullo di tamburi)

DIPENDE!

(mascella caduta)

Deluso? Te lo spiego tra un momento.

Innanzitutto, sono d'accordo sul fatto che entrambi sembrano avere differenze di prestazioni se si utilizza il tempo trascorso come metrica. Alcune persone hanno supportato questo fatto quando SQL Server converte le istruzioni COALESCE in CASE. Nel frattempo, ISNULL rimane così com'è.

Altri potrebbero ragionare in modo diverso a causa dei risultati variabili. Inoltre, per loro, convertire COALESCE in CASE è più veloce di quanto sbattiamo gli occhi. Proprio come quello che è stato sottolineato in questo thread, la differenza di prestazioni "è minuscola". Sono d'accordo. Ecco un altro articolo in cui si afferma che la differenza "è minima".

Tuttavia, ecco un grosso problema:possiamo fidarci di un minuscolo tempo trascorso come metrica? Ciò che conta davvero è quante letture logiche ha la query. È ciò che indicheremo nei nostri prossimi esempi.

(Dai un'occhiata al mio altro articolo sulle letture logiche e sul perché questo fattore ritarda le tue domande.)

Esempio 1

Esaminiamo lo stesso esempio e confrontiamo le loro letture logiche e i piani di esecuzione. Prima di eseguire questa operazione, assicurati che STATISTICS IO sia ATTIVO e Includi il piano di esecuzione effettivo è abilitato.

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

Ecco i fatti:

Le letture logiche per entrambe le query sono le stesse. Entrambi sono 107 * 8 KB di pagine. Se abbiamo un milione di record, le letture logiche aumenteranno, ovviamente. Ma le letture logiche per entrambe le query saranno uguali. Questo è il caso anche se COALESCE viene convertito in CASE:

Esaminiamo il piano di esecuzione. Ecco come lo faremo:

  1. Esegui la prima istruzione SELECT con l'espressione COALESCE.
  2. Fai clic sul Piano di esecuzione scheda nei risultati. Fare clic con il pulsante destro del mouse e selezionare Salva piano di esecuzione con nome . E nomina il file plan1.sqlplan .
  3. Esegui la seconda istruzione SELECT con la funzione ISNULL.
  4. Fai clic sul Piano di esecuzione scheda nei risultati.
  5. Fai clic con il pulsante destro del mouse e seleziona Confronta Showplan .
  6. Seleziona il file plan1.sqlplan . Apparirà una nuova finestra.

È così che esamineremo il piano di esecuzione per tutti gli esempi.

Tornando al nostro primo esempio, vedere la Figura 6 per vedere il confronto del piano di esecuzione:

Hai notato questi punti importanti nella Figura 6?

  • La parte ombreggiata dei 2 piani (le scansioni dell'indice) indica che SQL Server ha utilizzato le stesse operazioni per le 2 query.
  • Il QueryPlanHash per i 2 piani è 0x27CEB4CCE12DA5E7, il che significa che il piano è lo stesso per entrambi.
  • Le differenze di pochi millisecondi per il tempo trascorso sono trascurabili.

Da asporto

È come confrontare le mele con le mele, ma di tipi diversi. Una è una mela Fuji del Giappone, un'altra è una mela rossa di New York. Tuttavia, sono entrambe mele.

Allo stesso modo, SQL Server richiede le stesse risorse e il piano di esecuzione scelto per entrambe le query. L'unica differenza è l'uso di COALESCE o ISNULL. Piccole differenze, in quanto il risultato finale è lo stesso.

Esempio 2

La grande differenza appare quando usi una sottoquery come argomento sia per COALESCE che per 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)

Il codice sopra avrà lo stesso risultato, ma l'interno è molto diverso.

Cominciamo con le letture logiche:

L'istruzione SELECT con l'espressione COALESCE ha il doppio delle letture logiche di quella che utilizzava ISNULL.

Ma perché raddoppiare le letture logiche? Il confronto del piano di esecuzione rivelerà ancora di più:

La Figura 8 spiega perché le letture logiche sono doppie utilizzando COALESCE. Vedi i 2 nodi Stream Aggregate nel piano in basso:sono duplicati. La domanda successiva è:perché è stato duplicato?

Ricordiamo che il punto si riferisce a quando COALESCE viene convertito in CASE. Quante volte vengono valutate le espressioni negli argomenti? DUE VOLTE!

Quindi, la sottoquery viene valutata due volte. Viene visualizzato nel piano di esecuzione con nodi duplicati.

Questo spiega anche le doppie letture logiche usando COALESCE rispetto a ISNULL. Se prevedi di guardare l'XML del piano di esecuzione della query con COALESCE, è piuttosto lungo. Ma rivela che la sottoquery verrà eseguita due volte.

E adesso? Possiamo superare in astuzia questo? Ovviamente! Se hai mai affrontato qualcosa del genere, cosa che credo sia rara, la soluzione possibile è dividere e conquistare. Oppure, usa ISNULL se è solo una sottoquery.

Come evitare di valutare due volte l'espressione della sottoquery

Ecco come evitare di valutare la sottoquery due volte:

  • Dichiara una variabile e assegna ad essa il risultato della sottoquery.
  • Quindi, passa la variabile come argomento a COALESCE.
  • Ripeti gli stessi passaggi a seconda del numero di sottoquery.

Come ho detto, dovrebbe essere raro, ma se succede, sai cosa fare ora.

Alcune parole sul livello di isolamento

La valutazione della sottoquery due volte può causare un altro problema. A seconda del livello di isolamento della query, il risultato della prima valutazione potrebbe essere diverso dal secondo in un ambiente multiutente. È pazzesco.

Per garantire che i risultati restino stabili, puoi provare a utilizzare un ISOLAMENTO ISTANTANEO. Inoltre, puoi usare ISNULL. Oppure, può essere un approccio divide et impera, come indicato sopra.

Da asporto

Allora, qual è l'essenza?

  • Controlla sempre le letture logiche. Conta più del tempo trascorso. Usa il tempo trascorso e porta via la tua sanità mentale. La tua macchina e il server di produzione avranno sempre risultati variabili. Concediti una pausa.
  • Controlla sempre il piano di esecuzione, così sai cosa sta succedendo sotto il cofano.
  • Tieni presente che quando COALESCE viene tradotto in CASE, le espressioni vengono valutate due volte. Quindi, una sottoquery o qualcosa di simile può essere un problema. Assegnare il risultato della sottoquery a una variabile prima di utilizzarla in COALESCE può essere una soluzione.
  • Ciò che è più veloce dipende dai risultati delle letture logiche e dai piani di esecuzione. Non esiste una regola generale per determinare se COALESCE o ISNULL è più veloce. In caso contrario, Microsoft potrebbe informarne, come ha fatto in HierarchyID e SQL Graph.

Alla fine, dipende davvero.

Conclusione

Spero che tu abbia avuto la pena di leggere questo articolo. Ecco i punti di cui abbiamo discusso:

  • COALESCE è uno dei modi per gestire i null. È una rete di sicurezza per evitare errori di codice.
  • Accetta l'elenco degli argomenti e restituisce il primo valore non nullo.
  • Viene convertito in un'espressione CASE durante l'elaborazione della query, ma non rallenta la query.
  • Sebbene ci siano alcune somiglianze con ISNULL, ci sono 7 differenze notevoli.
  • Può essere utilizzato con la clausola WHERE.
  • Infine, non è né più veloce né più lento di ISNULL.

Se ti piace questo post, i pulsanti dei social media aspettano il tuo clic. La condivisione è cura.

Grazie.

Leggi anche

Gestire efficacemente i valori NULL con la funzione SQL COALESCE per principianti

Un uso pratico della funzione SQL COALESCE