sql >> Databasteknik >  >> RDS >> Sqlserver

De bästa svaren på 5 brännande frågor om COALESCE-funktionen i SQL Server

Hur cool är COALESCE-funktionen i SQL?

Det är coolt nog att vara så viktigt för mig. Och jag kommer mer än gärna att anställa en ny kille som inte har en dålig vana att ignorera målet med COALESCE. Det inkluderar andra uttryck och funktioner för att hantera liknande situationer.

Idag hittar du svaren på de fem mest ställda frågorna om SQL COALESCE-uttryck. En av dessa diskuteras om och om igen.

Ska vi börja?

Vad är användningen av COALESCE-funktionen i SQL?

Det kan besvaras med två ord:hantering av nollor .

Null är ett tomrum av värderingar. Okänd med andra ord. Det skiljer sig från en tom sträng eller ett nolltal. Att hantera nollvärden kräver användning av uttryck och funktioner. En av dem är COALESCE.

För att förstå vad jag menar, se påståendena nedan:

DECLARE @number INT

SELECT @number + 33587

Kommer det att gå bra? Det kommer.

Är något fel? Inga för tillfället.

Men satserna kommer att resultera i NULL eftersom att lägga till null till ett tal är lika med NULL.

Om alla dina frågor bara faller till denna nivå kan du sluta läsa. Men det är de naturligtvis inte. Vi får betalt för mer än att producera den här typen av kod.

Låt oss nu lägga till lite "katastrof":

DECLARE @number INT

SET @number = @number + 33587

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

PRINT 'Success!'

Exekveringen av koden ovan kommer att vara i återvändsgränd när den når UPDATE-satsen. Det kommer inte att skriva ut "Framgång!" eftersom du inte kan sätta en noll på en icke-nullbar kolumn. Säger detta uttalande tydligt varför vi behöver hantera nollor?

Låt oss ändra koden för att lägga till ett skyddsnät:

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 kommer att ändra nollvärdet till noll, och en summa blir inte noll.

Lärdomen är att COALESCE är ett av säkerhetsnäten mot null. Ännu bättre, att hantera nollor korrekt i din SQL-kod minskar din huvudvärk och låter dig gå hem tidigt. Det är säkert.

Nu förstår du varför jag vill ha någon i mitt team som är flitig i att hantera nullor.

Fler praktiska exempel på användningen av SQL COALESCE

Låt oss hänvisa till mer praktiska exempel.

Anta att du bor i en region där vissa människor har mellannamn, men andra inte. Hur kommer du att bilda det fullständiga namnet av förnamn, mellannamn och efternamn utan att falla i nollfällan?

Här är en möjlig lösning med COALESCE:

USE AdventureWorks
GO

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

Ett annat exempel:anta att du är anställd i ett företag där bruttolönen beräknas på olika sätt för varje anställd. För några av dem finns timpriser. Andra får betalt till vecko- eller månadsavgifter.

Här är ett tabellexempel tillsammans med en frågelösning med 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;

Tabellen innehåller olika lönesätt per anställd-ID. Frågan kräver att du anger en månadslön för alla.

Det är här COALESCE kommer att lysa:den accepterar en lista med värden, och det kan finnas hur många objekt som helst. COALESCE väljer den första som inte är null:

Snyggt, eller hur?

Hur fungerar COALESCE i SQL?

Definitionen av COALESCE är ett uttryck som returnerar det första icke-nullvärdet från en lista med värden. COALESCE-syntaxen är:

COALESCE ( uttryck [ ,…n ] )

Vårt tidigare exempel med olika betalningssätt för löner illustrerar detta.

Vad finns under huven

Under huven är COALESCE-funktionen i SQL ett sockerbelagt uttryck för ett mycket längre CASE-uttryck. Det eliminerar behovet av att skriva ett likvärdigt CASE, som är längre (och tröttsamt, för lata maskinskrivare som jag). Resultatet blir detsamma.

Kan vi bevisa det? ja! För det första erkänner Microsoft det.

Men bra för oss, Microsoft inkluderade det i exekveringsplanen. Därmed vet vi vad som händer.

Låt oss prova det med ett tidigare exempel med löner. Men innan du kör frågan nedan igen, aktivera Inkludera faktisk exekveringsplan eller tryck bara på CTRL-M .

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

Klicka på Utförandeplan fliken i resultaten. Det ser enkelt ut, men vår dolda pärla ligger i Compute Scalar nod. När du håller musen över det ser du ett uttryck som heter Expr1002 (Figur 2). Vad kan det vara?

Låt oss gräva djupare. Högerklicka på den och välj Visa Execution Plan XML . Ett nytt fönster visas. Ta en titt på figur 3 nedan:

Där är ditt CASE-uttalande. Nedan är det hela formaterat och indraget för läsbarhet:

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

Det är ganska långt jämfört med

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

Det är vad SQL Server gjorde med vår fråga med COALESCE. Allt är för att få det första värdet som inte är null i en lista med värden.

Kan det bli kortare?

Jag vet vad du tänker. Om SQL Server gör det under frågebehandling måste COALESCE vara långsam. För att inte tala om de många framträdandena av CONVERT_IMPLICIT. Kommer du hellre att använda alternativ?

För det första kan du skriva ett kortare CASE-uttryck själv. Eller så kan du använda ISNULL. Mer om det senare. På tal om att vara långsam, jag hade det täckt innan det här inlägget slutar.

Vad är skillnaderna mellan COALESCE och ISNULL i SQL?

Ett av alternativen till COALESCE är ISNULL. Att använda COALESCE med 2 värden gör att det liknar ISNULL. Åtminstone ser resultaten liknande ut. Ändå finns det anmärkningsvärda skillnader. Du kan använda den som en guide för att bestämma om du ska använda COALESCE eller ISNULL.

(1) ISNULL accepterar 2 argument. COALESCE accepterar en lista med argument

Det är den mest uppenbara skillnaden. Från syntaxen är det säkert annorlunda.

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

När du använder båda med 2 argument blir resultaten desamma. De två påståendena nedan kommer att resultera i 1:

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

Även om resultaten är desamma, menas de annorlunda:

  • ISNULL(NULL, 1) returnerade 1 eftersom det första argumentet är NULL.
  • COALESCE(NULL, 1) returnerade 1 eftersom 1 är det första icke-nullvärdet i listan .

(2) COALESCE är SQL-92 Standard

Det är rätt. Du kan kontrollera det. Om du till exempel vill porta din SQL-kod till MySQL från SQL Server kommer COALESCE att fungera på samma sätt. Se figur 4 och jämför resultatet från figur 1:

Att använda ISNULL i MySQL utlöser dock ett fel om du använder SQL Servers syntax.

t.ex. kör följande i SQL Server Management Studio och MySQL Workbench:

SELECT ISNULL(null,1)

Vad hände? I SQL Server är utdata 1. Men i MySQL är utdata ett fel:

06:36:52 SELECT ISNULL(null,1) Felkod:1582. Fel parameterantal i anropet till den ursprungliga funktionen 'ISNULL'

Saken är att ISNULL i MySQL accepterar 1 argument och returnerar 1 om argumentet är null. Annars returnerar den 0.

(3) Att godkänna 2 nollor i COALESCE utlöser ett fel. Det är bra med ISNULL

Detta kommer att utlösa ett fel:

SELECT COALESCE(NULL, NULL)

Felet är:"Minst ett av argumenten till COALESCE måste vara ett uttryck som inte är NULL-konstanten."

Det här kommer att gå bra:

SELECT ISNULL(NULL, NULL)

Att ändra COALESCE-koden till något liknande nedan kommer inte att utlösa ett fel:

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

Det hände på grund av @value är inte en nollkonstant.

(4) SQL COALESCE konverteras till CASE. ISNULL förblir ISNULL

Vi har sett detta i 'Hur fungerar COALESCE i SQL?' sektion. Här, låt oss undersöka ett annat exempel:

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

Inspektion av Execution Plan XML för skaläroperatorn avslöjar konverteringen till 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

Kör nu en motsvarande fråga med ISNULL:

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

Inspektera sedan Execution Plan XML för skaläroperatorn:

 [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 är fortfarande ISNULL.

(5) Datatypen för det resulterande uttrycket är annorlunda

Datatypsbestämning av det resulterande uttrycket skiljer sig också mellan COALESCE och ISNULL:

  • ISNULL använder datatypen för den första parametern.
  • COALESCE returnerar datatypen för värdet med högst prioritet.

För en lista över datatypers prioritet, kolla in den här länken.

Låt oss ta ett exempel:

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

Inspektera sedan konverteringen till CASE i 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

I CASE-uttrycket ovan kommer datatypen för resultatet att vara numeric(19,4).

Varför? Det har högre företräde än pengar och småpengar även om du CASTAR det till pengar . Varför numerisk och inte pengar ? På grund av konstanten 0,0000.

Om du undrar vad @1 är, Execution Plan XML har svaret. Det är det konstanta talet 4.

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

Låt oss prova det med ISNULL:

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

Återigen, leta efter Scalar Operator s ScalarString :

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

Slutligen kommer datatypen för det resulterande uttrycket att vara pengar . Det är datatypen för det första argumentet.

Hur överlista dataprioritet

Du kan "överlista" dataprioritet genom att lägga till några ändringar i din kod. Tidigare hade resultatet ett numeriskt data typ. Om du vill att resultatet ska bli en pengar datatyp och bli av med CONVERT_IMPLICIT, gör följande:

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

Lade du märke till konstanterna ($4,000) och ($0,0000)? Det är pengar konstanter. Vad som händer härnäst visas i Execution Plan XML 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

Det är mycket bättre. Den är kortare och CONVERT_IMPLICIT är borta. Och den resulterande datatypen är pengar .

(6) Nullbarheten för det resulterande uttrycket är annorlunda

ISNULL(NULL, 1) och COALESCE(NULL, 1) har liknande resultat, men deras nullbarhetsvärden är olika. COALESCE är nullbar. ISNULL är det inte. Du kan se detta när du använder det på beräknade kolumner.

Låt oss hänvisa till ett exempel. Uttrycket nedan kommer att utlösa ett fel eftersom PRIMARY KEY inte kan acceptera NULL-värden. Samtidigt är nullbarheten för COALESCE-uttrycket för kolumn2 utvärderas till NULL.

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

Detta uttalande lyckas eftersom nullbarheten för ISNULL-funktionen utvärderas SOM INTE NULL.

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

(7) ISNULLs vänstra argument utvärderas en gång. Det är tvärtom med COALESCE

Betrakta det föregående exemplet igen:

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

Inspektera sedan ScalarString för detta:

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

När COALESCE-funktionen i SQL konverteras till ett CASE, utvärderas varje uttryck två gånger (förutom det sista). Som du kan se ovan, timmepris*22,00*8,00 dök upp två gånger. Samma sak med weekly_rate*4.00 . Det sista uttrycket, monthly_rate , dök upp en gång.

Eftersom COALESCE kommer att utvärdera uttryck två gånger, kan det bli en prestationsstraff. Mer om detta senare.

Men kolla in ISNULL-motsvarigheten:

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

Sedan inspekterar vi ScalarString i Execution Plan 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))

Som du kan se ovan, timpris , veckopris och månadspris dykt upp endast en gång. Så du behöver inte oroa dig för att uttryck ska utvärderas två gånger med ISNULL.

Kan vi använda COALESCE i en WHERE-klausul?

Visst. Det finns inget bättre sätt än att visa ett exempel för att bevisa detta.

-- 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 returnerar en tom sträng om Mellannamn är inget. Naturligtvis finns det ett kortare sätt att producera resultatet. Men detta visar att COALESCE fungerar i en WHERE-klausul.

Vilket är snabbare:COALESCE eller ISNULL?

Äntligen har vi kommit till ett hett ämne:Prestanda!

Du kommer att få många sidor med tester och jämförelser, men det kommer att bli en kamp mellan COALESCE och ISNULL-förespråkare i kommentarerna. Vi kommer att rensa ut damm och rök från dessa krig.

Vilket är snabbare:COALESCE eller ISNULL? Låt mig börja med att säga att svaret är:

(trummor rullar)

DET BERÖR!

(käken tappade)

Besviken? Jag ska förklara det om en stund.

För det första håller jag med om att båda verkar ha prestandaskillnader om du använder förfluten tid som mätvärde. Vissa personer stödde detta faktum när SQL Server översätter COALESCE till CASE-satser. Under tiden förblir ISNULL som den är.

Andra kan resonera annorlunda på grund av de varierande resultaten. För dem är det också snabbare att konvertera COALESCE till CASE än att vi blinkar med ögonen. Precis som det som påpekas i den här tråden är prestandaskillnaden "miniscul". Jag håller med. Här är en annan artikel som sa att skillnaden "är liten."

Men här är en stor sak:kan vi lita på en minimal förfluten tid som ett mått? Det som verkligen betyder något är hur mycket logisk läsning frågan har. Det är vad vi kommer att påpeka i våra nästa exempel.

(Kolla in min andra artikel om logiska läsningar och varför denna faktor släpar efter dina frågor.)

Exempel 1

Låt oss undersöka samma exempel och jämföra deras logiska läsningar och genomförandeplaner. Innan du kör detta, se till att STATISTICS IO är PÅ och Inkludera faktisk exekveringsplan är aktiverad.

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

Här är fakta:

Logiska läsningar för båda frågorna är desamma. Båda är 107 * 8KB sidor. Om vi ​​har en miljon poster kommer logiska läsningar att öka, förstås. Men de logiska läsningarna för båda frågorna kommer att vara lika. Så är fallet även om COALESCE konverteras till CASE:

Låt oss inspektera genomförandeplanen. Så här ska vi göra:

  1. Kör den första SELECT-satsen med COALESCE-uttrycket.
  2. Klicka på Exekutionsplan fliken i resultat. Högerklicka på den och välj Spara exekveringsplan som . Och namnge filen plan1.sqlplan .
  3. Kör den andra SELECT-satsen med ISNULL-funktionen.
  4. Klicka på Exekutionsplan fliken i resultat.
  5. Högerklicka på den och välj Jämför Showplan .
  6. Välj filen plan1.sqlplan . Ett nytt fönster visas.

Det är så vi kommer att inspektera genomförandeplanen för alla exempel.

För att återgå till vårt första exempel, se figur 6 för att se jämförelsen av genomförandeplanen:

Lade du märke till dessa viktiga punkter i figur 6?

  • Den skuggade delen av de två planerna (indexsökningarna) betyder att SQL Server använde samma operationer för de två frågorna.
  • QueryPlanHash för de två planerna är 0x27CEB4CCE12DA5E7, vilket betyder att planen är densamma för båda.
  • De få millisekundersskillnaderna för förfluten tid är försumbara.

Hämtmat

Det är som att jämföra äpplen med äpplen, men av olika typer. Ett är ett Fuji-äpple från Japan, ett annat är ett rött äpple från New York. Ändå är de båda äpplen.

På samma sätt kräver SQL Server samma resurser och den valda exekveringsplanen för båda frågorna. Den enda skillnaden är användningen av COALESCE eller ISNULL. Mindre skillnader, eftersom slutresultatet är detsamma.

Exempel 2

Den stora skillnaden uppstår när du använder en underfråga som argument för både COALESCE och 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)

Ovanstående kod kommer att få samma resultat, men insidan är väldigt annorlunda.

Låt oss börja med de logiska läsningarna:

SELECT-satsen med COALESCE-uttrycket har dubbla logiska läsningar av den som använde ISNULL.

Men varför dubbla de logiska läsningarna? Jämförelsen av genomförandeplanen kommer att avslöja ännu mer:

Figur 8 förklarar varför de logiska avläsningarna är dubbla med COALESCE. Se de 2 Stream Aggregate-noderna i den nedre planen:de är dubbletter. Nästa fråga är varför den duplicerades?

Låt oss komma ihåg punkten när COALESCE konverteras till CASE. Hur många gånger utvärderas uttrycken i argumenten? TVÅ GÅNGER!

Så underfrågan utvärderas två gånger. Det visas i exekveringsplanen med dubbletter av noder.

Detta förklarar också dubbla logiska läsningar med COALESCE jämfört med ISNULL. Om du planerar att titta på exekveringsplanens XML för frågan med COALESCE, är den ganska lång. Men det avslöjar att underfrågan kommer att köras två gånger.

Nu då? Kan vi överlista detta? Självklart! Om du någonsin mött något liknande, vilket jag tror är sällsynt, är den möjliga lösningen att dela och erövra. Eller använd ISNULL om det bara är en underfråga.

Hur du undviker att utvärdera underfrågans uttryck två gånger

Så här undviker du att utvärdera underfrågan två gånger:

  • Deklarera en variabel och tilldela resultatet av underfrågan till den.
  • Skicka sedan variabeln som ett argument till COALESCE.
  • Upprepa samma steg beroende på antalet underfrågor.

Det borde som sagt vara sällsynt, men om det händer vet du vad du ska göra nu.

Några ord på isoleringsnivå

Att utvärdera underfrågan två gånger kan orsaka ytterligare ett problem. Beroende på din frågas isoleringsnivå kan resultatet av den första utvärderingen skilja sig från den andra i en miljö med flera användare. Det är galet.

För att säkerställa att de stabila resultaten återkommer kan du prova att använda en SNAPSHOT ISOLATION. Du kan också använda ISNULL. Eller så kan det vara en dela-och-härska-strategi, som påpekats ovan.

Hämtmat

Så, vad är kärnan?

  • Kontrollera alltid de logiska läsningarna. Det betyder mer än förfluten tid. Använd förfluten tid och ta bort ditt förstånd. Din maskin och produktionsservern kommer alltid att ha varierande resultat. Ge dig själv en paus.
  • Kontrollera alltid utförandeplanen så att du vet vad som händer under huven.
  • Var medveten om att när COALESCE översätts till CASE, utvärderas uttrycken två gånger. Då kan en underfråga eller något liknande vara ett problem. Att tilldela underfrågans resultat till en variabel innan den används i COALESCE kan vara en lösning.
  • Vad som är snabbare beror på de logiska läsningarnas resultat och genomförandeplaner. Det finns ingen generell regel för att avgöra om COALESCE eller ISNULL är snabbare. Annars kan Microsoft informera om det, som de gjorde i HierarchyID och SQL Graph.

Så småningom beror det verkligen på.

Slutsats

Jag hoppas att du hade en värd att läsa den här artikeln. Här är punkterna vi diskuterade:

  • COALESCE är ett av sätten att hantera nollor. Det är ett säkerhetsnät för att undvika fel i koden.
  • Den accepterar argumentlistan och returnerar det första icke-nullvärdet.
  • Det konverteras till ett CASE-uttryck under frågebehandlingen, men det gör inte frågan långsammare.
  • Även om det finns några likheter med ISNULL, finns det sju anmärkningsvärda skillnader.
  • Den kan användas med WHERE-satsen.
  • Slutligen är det inte snabbare eller långsammare än ISNULL.

Om du gillar det här inlägget väntar knapparna på sociala medier på ditt klick. Att dela är att bry sig.

Tack.

Läs också

Hantera NULL-värdena effektivt med SQL COALESCE-funktionen för nybörjare

En praktisk användning av SQL COALESCE-funktionen


  1. bra postgresql-klient för Windows?

  2. LEFT() vs SET TEXTSIZE i SQL Server:Vad är skillnaden?

  3. Hur man designar en databasmodell för ett biobokningssystem

  4. PostgreSQL:Ta bort attribut från JSON-kolumnen