Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Top-Antworten auf 5 brennende Fragen zur COALESCE-Funktion in SQL Server

Wie cool ist die COALESCE-Funktion in SQL?

Es ist cool genug, mir so wichtig zu sein. Und ich werde mehr als glücklich sein, einen neuen Mann einzustellen, der nicht die schlechte Angewohnheit hat, das Ziel von COALESCE zu ignorieren. Dazu gehören andere Ausdrücke und Funktionen zur Handhabung ähnlicher Situationen.

Heute finden Sie die Antworten auf die fünf am häufigsten gestellten Fragen zum SQL COALESCE-Ausdruck. Eine davon wird immer wieder diskutiert.

Sollen wir anfangen?

Was ist die Verwendung der COALESCE-Funktion in SQL?

Es kann in 2 Worten beantwortet werden:Umgang mit Nullen .

Null ist eine Leere von Werten. Mit anderen Worten, unbekannt. Es unterscheidet sich von einer leeren Zeichenfolge oder einer Nullzahl. Die Handhabung von Nullen erfordert die Verwendung von Ausdrücken und Funktionen. Eine davon ist COALESCE.

Um zu verstehen, was ich meine, sehen Sie sich die folgenden Aussagen an:

DECLARE @number INT

SELECT @number + 33587

Wird es gut laufen? Das wird.

Gibt es ein Problem? Im Moment keine.

Aber die Anweisungen ergeben NULL, weil das Hinzufügen von Null zu einer Zahl gleich NULL ist.

Wenn alle Ihre Abfragen nur auf diese Ebene fallen, können Sie aufhören zu lesen. Aber das sind sie natürlich nicht. Wir werden für mehr bezahlt, als nur für die Erstellung dieser Art von Code.

Jetzt fügen wir ein bisschen „Katastrophe“ hinzu:

DECLARE @number INT

SET @number = @number + 33587

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

PRINT 'Success!'

Die Ausführung des obigen Codes befindet sich an der Sackgasse, wenn er die UPDATE-Anweisung erreicht. Es wird nicht „Erfolg!“ gedruckt, da Sie keine Null in eine Spalte schreiben können, die keine Nullwerte zulässt. Macht diese Aussage deutlich, warum wir mit Nullen umgehen müssen?

Lassen Sie uns den Code ändern, um ein Sicherheitsnetz hinzuzufügen:

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 ändert den Nullwert in Null, und eine Summe ist nicht Null.

Die Lektion ist, dass COALESCE eines der Sicherheitsnetze gegen Nullen ist. Noch besser, der richtige Umgang mit Nullen in Ihrem SQL-Code reduziert Ihre Kopfschmerzen und lässt Sie früh nach Hause gehen. Das ist sicher.

Jetzt verstehen Sie, warum ich jemanden in meinem Team haben möchte, der gewissenhaft mit Nullen umgeht.

Weitere praktische Beispiele zur Verwendung von SQL COALESCE

Lassen Sie uns auf weitere praktische Beispiele verweisen.

Angenommen, Sie leben in einer Region, in der einige Menschen einen zweiten Vornamen haben, andere jedoch nicht. Wie bilden Sie den vollständigen Namen aus dem Vornamen, dem zweiten Vornamen und dem Nachnamen, ohne in die Nullfalle zu tappen?

Hier ist eine mögliche Lösung mit COALESCE:

USE AdventureWorks
GO

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

Ein weiteres Beispiel:Angenommen, Sie sind Angestellter in einem Unternehmen, in dem der Bruttolohn für jeden Mitarbeiter anders berechnet wird. Für einige von ihnen gibt es Stundensätze. Andere werden zu wöchentlichen oder monatlichen Raten bezahlt.

Hier ist ein Tabellenbeispiel zusammen mit einer Abfragelösung mit 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;

Die Tabelle enthält verschiedene Zahlungsarten pro Mitarbeiter-ID. Die Abfrage erfordert, dass Sie ein monatliches Gehalt für alle ausgeben.

Hier wird COALESCE glänzen:Es akzeptiert eine Liste von Werten, und es kann eine beliebige Anzahl von Elementen geben. COALESCE wählt die erste aus, die nicht null ist:

Ordentlich, nicht wahr?

Wie funktioniert COALESCE in SQL?

Die Definition von COALESCE ist ein Ausdruck, der den ersten Nicht-Null-Wert aus einer Werteliste zurückgibt. Die COALESCE-Syntax lautet:

COALESCE ( Ausdruck [ ,…n ] )

Unser vorheriges Beispiel mit unterschiedlichen Auszahlungsarten für Löhne verdeutlicht dies.

Was ist unter der Haube?

Unter der Haube ist die COALESCE-Funktion in SQL ein mit Zucker überzogener Ausdruck für einen viel längeren CASE-Ausdruck. Es eliminiert die Notwendigkeit, einen äquivalenten CASE zu tippen, der länger ist (und ermüdend für faule Schreiber wie mich). Das Ergebnis ist dasselbe.

Können wir es beweisen? Ja! Zum einen gibt Microsoft es zu.

Aber gut für uns, Microsoft hat es in den Ausführungsplan aufgenommen. Somit wissen wir, was los ist.

Versuchen wir es anhand eines vorherigen Beispiels mit Löhnen. Aber bevor Sie die folgende Abfrage erneut ausführen, aktivieren Sie Aktuellen Ausführungsplan einschließen oder drücken Sie einfach STRG-M .

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

Klicken Sie auf den Ausführungsplan Registerkarte in den Ergebnissen. Es sieht einfach aus, aber unser verstecktes Juwel liegt im Compute Scalar Knoten. Wenn Sie die Maus darüber bewegen, sehen Sie einen Ausdruck namens Expr1002 (Figur 2). Was könnte das sein?

Lassen Sie uns tiefer graben. Klicken Sie mit der rechten Maustaste darauf und wählen Sie Ausführungsplan-XML anzeigen aus . Ein neues Fenster wird angezeigt. Schauen Sie sich Abbildung 3 unten an:

Da ist Ihre CASE-Anweisung. Unten ist das Ganze zur besseren Lesbarkeit formatiert und eingerückt:

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

Das ist ziemlich lang im Vergleich zu

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

Das hat SQL Server mit unserer Abfrage mit COALESCE gemacht. All dient dazu, den ersten Wert in einer Liste von Werten zu erhalten, der nicht null ist.

Geht es kürzer?

Ich weiß was du denkst. Wenn SQL Server dies während der Abfrageverarbeitung tut, muss COALESCE langsam sein. Ganz zu schweigen von den mehrfachen Auftritten von CONVERT_IMPLICIT. Werden Sie lieber Alternativen nutzen?

Zum einen können Sie selbst eine kürzere CASE-Anweisung eingeben. Oder Sie können ISNULL verwenden. Dazu später mehr. Apropos langsam sein, ich hatte das abgedeckt, bevor dieser Beitrag endet.

Was sind die Unterschiede zwischen COALESCE und ISNULL in SQL?

Eine der Alternativen zu COALESCE ist ISNULL. Die Verwendung von COALESCE mit 2 Werten ähnelt ISNULL. Zumindest sehen die Ergebnisse ähnlich aus. Dennoch gibt es bemerkenswerte Unterschiede. Sie können es als Leitfaden verwenden, um zu entscheiden, ob Sie COALESCE oder ISNULL verwenden.

(1) ISNULL Akzeptiert 2 Argumente. COALESCE akzeptiert eine Liste von Argumenten

Es ist der offensichtlichste Unterschied. Von der Syntax her ist es sicher anders.

ISNULL ( Prüfausdruck , Ersatzwert )
COALESCE ( Ausdruck [ ,…n ] )

Wenn Sie beide mit 2 Argumenten verwenden, sind die Ergebnisse gleich. Die 2 Anweisungen unten ergeben 1:

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

Die Ergebnisse sind zwar gleich, aber anders gemeint:

  • ISNULL(NULL, 1) hat 1 zurückgegeben, weil das erste Argument NULL ist.
  • COALESCE(NULL, 1) hat 1 zurückgegeben, da 1 der erste Nicht-Null-Wert in der Liste ist .

(2) COALESCE ist SQL-92-Standard

Stimmt. Du kannst es überprüfen. Wenn Sie beispielsweise Ihren SQL-Code von SQL Server nach MySQL portieren möchten, funktioniert COALESCE genauso. Siehe Abbildung 4 und vergleichen Sie das Ergebnis von Abbildung 1:

Die Verwendung von ISNULL in MySQL löst jedoch einen Fehler aus, wenn Sie die Syntax von SQL Server verwenden.

Führen Sie beispielsweise Folgendes in SQL Server Management Studio und MySQL Workbench aus:

SELECT ISNULL(null,1)

Was ist passiert? In SQL Server ist die Ausgabe 1. Aber in MySQL ist die Ausgabe ein Fehler:

06:36:52 SELECT ISNULL(null,1) Fehlercode:1582. Falsche Parameteranzahl im Aufruf der nativen Funktion „ISNULL“

Die Sache ist, dass ISNULL in MySQL 1 Argument akzeptiert und 1 zurückgibt, wenn das Argument null ist. Andernfalls wird 0 zurückgegeben.

(3) Das Übergeben von 2 Nullen in COALESCE löst einen Fehler aus. Mit ISNULL ist das in Ordnung

Dies löst einen Fehler aus:

SELECT COALESCE(NULL, NULL)

Der Fehler lautet:„Mindestens eines der Argumente für COALESCE muss ein Ausdruck sein, der nicht die NULL-Konstante ist.“

Das wird in Ordnung sein:

SELECT ISNULL(NULL, NULL)

Das Ändern des COALESCE-Codes in etwas Ähnliches wie unten löst keinen Fehler aus:

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

Das ist passiert, weil @value ist keine Nullkonstante.

(4) SQL COALESCE wird in CASE umgewandelt. ISNULL bleibt ISNULL

Wir haben dies in „Wie funktioniert COALESCE in SQL?“ gesehen Sektion. Sehen wir uns hier ein weiteres Beispiel an:

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

Prüfung der Ausführungsplan-XML für den Skalaroperator zeigt die Umwandlung 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

Führen Sie nun eine entsprechende Abfrage mit ISNULL:

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

Überprüfen Sie dann die Execution Plan XML für den Skalaroperator:

 [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 ist immer noch ISNULL.

(5) Der Datentyp des resultierenden Ausdrucks ist unterschiedlich

Die Datentypbestimmung des resultierenden Ausdrucks unterscheidet sich auch zwischen COALESCE und ISNULL:

  • ISNULL verwendet den Datentyp des ersten Parameters.
  • COALESCE gibt den Datentyp des Werts mit der höchsten Priorität zurück.

Eine Liste der Prioritäten von Datentypen finden Sie unter diesem Link.

Nehmen wir ein Beispiel:

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

Überprüfen Sie dann die Konvertierung in CASE im 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

Im obigen CASE-Ausdruck ist der Datentyp des Ergebnisses numeric(19,4).

Wieso den? Es hat Vorrang vor Geld und Kleingeld selbst wenn Sie es in Geld umwandeln . Warum numerisch und nicht Geld ? Wegen der Konstante 0.0000.

Falls Sie sich fragen, was @1 ist, die Ausführungsplan-XML hat die Antwort. Es ist die Konstante Nummer 4.

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

Versuchen wir es mit ISNULL:

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

Suchen Sie erneut nach dem Skalaroperator 's ScalarString :

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

Schließlich ist der Datentyp des resultierenden Ausdrucks Geld . Es ist der Datentyp des ersten Arguments.

Wie man die Datenpriorität überlistet

Sie können die Datenpriorität „überlisten“, indem Sie ein paar Änderungen an Ihrem Code vornehmen. Früher hatte das Ergebnis eine Zahl Datentyp. Wenn Sie möchten, dass das Ergebnis ein Geld ist Datentyp und entfernen Sie CONVERT_IMPLICIT, gehen Sie wie folgt vor:

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

Haben Sie die Konstanten ($4.000) und ($0.0000) bemerkt? Das ist Geld Konstanten. Was als Nächstes passiert, wird im Execution Plan XML angezeigt '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

Das ist viel besser. Es ist kürzer und CONVERT_IMPLICIT ist weg. Und der resultierende Datentyp ist Geld .

(6) Die NULL-Zulässigkeit des resultierenden Ausdrucks ist unterschiedlich

ISNULL(NULL, 1) und COALESCE(NULL, 1) haben ähnliche Ergebnisse, aber ihre NULL-Zulässigkeitswerte sind unterschiedlich. COALESCE ist nullable. ISNULL ist es nicht. Sie können dies sehen, wenn Sie es für berechnete Spalten verwenden.

Nehmen wir ein Beispiel. Die folgende Anweisung löst einen Fehler aus, da der PRIMARY KEY keine NULL-Werte akzeptieren kann. Gleichzeitig die Nullfähigkeit des COALESCE-Ausdrucks für column2 wird zu NULL ausgewertet.

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

Diese Anweisung ist erfolgreich, da die NULL-Zulässigkeit der ISNULL-Funktion als NOT NULL ausgewertet wird.

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

(7) Das linke Argument von ISNULL wird einmal ausgewertet. Bei COALESCE ist es das Gegenteil

Betrachten Sie noch einmal das vorherige Beispiel:

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

Untersuchen Sie dann den ScalarString dazu:

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

Wenn die COALESCE-Funktion in SQL in einen CASE konvertiert wird, wird jeder Ausdruck zweimal ausgewertet (mit Ausnahme des letzten). Wie Sie oben sehen können, hourly_rate*22.00*8.00 zweimal erschienen. Das Gleiche gilt für weekly_rate*4.00 . Der letzte Ausdruck, monthly_rate , erschien einmal.

Da COALESCE Ausdrücke zweimal auswertet, kann es zu Leistungseinbußen kommen. Dazu später mehr.

Sehen Sie sich jedoch das ISNULL-Äquivalent an:

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

Dann untersuchen wir den ScalarString im Ausführungsplan-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))

Wie Sie oben sehen können, hourly_rate , Wochenpreis und monthly_rate erschien nur einmal. Sie müssen sich also keine Sorgen machen, dass Ausdrücke mit ISNULL zweimal ausgewertet werden.

Können wir COALESCE in einer WHERE-Klausel verwenden?

Sichere Sache. Es gibt keinen besseren Weg, als ein Beispiel zu zeigen, um dies zu beweisen.

-- 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 gibt eine leere Zeichenfolge zurück, wenn MiddleName ist Null. Natürlich gibt es einen kürzeren Weg zum Ergebnis. Aber das zeigt, dass COALESCE in einer WHERE-Klausel funktioniert.

Was ist schneller:COALESCE oder ISNULL?

Endlich sind wir bei einem heißen Thema angelangt:Performance!

Sie werden viele Seiten mit Tests und Vergleichen erhalten, aber in den Kommentaren wird es einen Kampf zwischen COALESCE- und ISNULL-Befürwortern geben. Wir werden den Staub und Rauch dieser Kriege vertreiben.

Was ist schneller:COALESCE oder ISNULL? Lassen Sie mich zunächst sagen, dass die Antwort lautet:

(Trommelwirbel)

ES HÄNGT AB!

(Kiefer gesenkt)

Enttäuscht? Ich erkläre es gleich.

Erstens stimme ich zu, dass beide Leistungsunterschiede zu haben scheinen, wenn Sie die verstrichene Zeit als Metrik verwenden. Einige Leute unterstützten diese Tatsache, wenn SQL Server COALESCE in CASE-Anweisungen übersetzt. In der Zwischenzeit bleibt ISNULL wie es ist.

Andere mögen aufgrund der unterschiedlichen Ergebnisse anders argumentieren. Außerdem ist für sie die Umwandlung von COALESCE in CASE schneller, als wir mit den Augen blinzeln. Genau wie in diesem Thread darauf hingewiesen wird, ist der Leistungsunterschied „minimal“. Ich stimme zu. Hier ist ein weiterer Artikel, der besagt, dass der Unterschied „gering ist“.

Hier ist jedoch eine große Sache:Können wir einer winzigen verstrichenen Zeit als Metrik vertrauen? Was wirklich zählt, ist, wie viele logische Lesevorgänge die Abfrage hat. Darauf werden wir in unseren nächsten Beispielen hinweisen.

(Lesen Sie meinen anderen Artikel über logische Lesevorgänge und warum dieser Faktor Ihre Abfragen verzögert.)

Beispiel 1

Lassen Sie uns dasselbe Beispiel untersuchen und ihre logischen Lesevorgänge und Ausführungspläne vergleichen. Bevor Sie dies ausführen, vergewissern Sie sich, dass STATISTICS IO aktiviert ist und Aktuellen Ausführungsplan einschließen aktiviert ist.

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

Hier sind die Fakten:

Logische Lesevorgänge für beide Abfragen sind gleich. Beide sind 107 * 8 KB Seiten groß. Wenn wir eine Million Datensätze haben, werden die logischen Lesevorgänge natürlich zunehmen. Aber die logischen Lesevorgänge für beide Abfragen sind gleich. Das ist auch dann der Fall, wenn COALESCE in CASE:

umgewandelt wird

Sehen wir uns den Ausführungsplan an. So werden wir es machen:

  1. Führen Sie die 1. SELECT-Anweisung mit dem COALESCE-Ausdruck aus.
  2. Klicken Sie auf den Ausführungsplan Registerkarte in den Ergebnissen. Klicken Sie mit der rechten Maustaste darauf und wählen Sie Ausführungsplan speichern unter . Und nennen Sie die Datei plan1.sqlplan .
  3. Führen Sie die 2. SELECT-Anweisung mit der ISNULL-Funktion aus.
  4. Klicken Sie auf den Ausführungsplan Tab in den Ergebnissen.
  5. Klicken Sie mit der rechten Maustaste darauf und wählen Sie Showplan vergleichen .
  6. Wählen Sie die Datei plan1.sqlplan aus . Ein neues Fenster wird angezeigt.

So prüfen wir den Ausführungsplan für alle Beispiele.

Um auf unser erstes Beispiel zurückzukommen, siehe Abbildung 6, um den Vergleich der Ausführungspläne zu sehen:

Haben Sie diese wichtigen Punkte in Abbildung 6 bemerkt?

  • Der schattierte Teil der 2 Pläne (die Index-Scans) bedeutet, dass SQL Server dieselben Vorgänge für die 2 Abfragen verwendet hat.
  • Der QueryPlanHash für die 2 Pläne ist 0x27CEB4CCE12DA5E7, was bedeutet, dass der Plan für beide gleich ist.
  • Die wenigen Millisekunden-Unterschiede für die verstrichene Zeit sind vernachlässigbar.

Imbiss

Es ist, als würde man Äpfel mit Äpfeln vergleichen, aber von unterschiedlichen Sorten. Einer ist ein Fuji-Apfel aus Japan, ein anderer ist ein roter Apfel aus New York. Trotzdem sind sie beide Äpfel.

In ähnlicher Weise erfordert SQL Server dieselben Ressourcen und den ausgewählten Ausführungsplan für beide Abfragen. Der einzige Unterschied besteht in der Verwendung von COALESCE oder ISNULL. Geringfügige Unterschiede, da das Endergebnis dasselbe ist.

Beispiel 2

Der große Unterschied tritt auf, wenn Sie eine Unterabfrage als Argument für COALESCE und ISNULL verwenden:

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)

Der obige Code wird das gleiche Ergebnis haben, aber das Innere ist sehr unterschiedlich.

Beginnen wir mit den logischen Lesevorgängen:

Die SELECT-Anweisung mit dem COALESCE-Ausdruck hat doppelt so viele logische Lesevorgänge wie diejenige, die ISNULL verwendet hat.

Aber warum die logischen Lesevorgänge verdoppeln? Der Ausführungsplan-Vergleich verrät noch mehr:

Abbildung 8 erklärt, warum die logischen Lesevorgänge mit COALESCE doppelt sind. Siehe die 2 Stream Aggregate-Knoten im unteren Plan:Sie sind Duplikate. Die nächste Frage ist, warum wurde es dupliziert?

Erinnern wir uns an den Punkt, der sich darauf bezieht, wann COALESCE in CASE konvertiert wird. Wie oft werden die Ausdrücke in den Argumenten ausgewertet? ZWEIMAL!

Die Unterabfrage wird also zweimal ausgewertet. Es wird im Ausführungsplan mit doppelten Knoten angezeigt.

Dies erklärt auch doppelte logische Lesevorgänge mit COALESCE im Vergleich zu ISNULL. Wenn Sie sich den Ausführungsplan-XML der Abfrage mit COALESCE ansehen möchten, ist er ziemlich lang. Aber es zeigt, dass die Unterabfrage zweimal ausgeführt wird.

Was jetzt? Können wir das überlisten? Natürlich! Wenn Sie jemals mit so etwas konfrontiert wurden, was meines Erachtens selten vorkommt, besteht die mögliche Lösung darin, zu teilen und zu erobern. Oder verwenden Sie ISNULL, wenn es sich nur um eine Unterabfrage handelt.

So vermeiden Sie die doppelte Auswertung des Unterabfrageausdrucks

So vermeiden Sie, dass die Unterabfrage zweimal ausgewertet wird:

  • Deklarieren Sie eine Variable und weisen Sie ihr das Ergebnis der Unterabfrage zu.
  • Übergeben Sie dann die Variable als Argument an COALESCE.
  • Wiederholen Sie dieselben Schritte je nach Anzahl der Unterabfragen.

Wie gesagt, es sollte selten vorkommen, aber wenn es passiert, wissen Sie jetzt, was zu tun ist.

Ein paar Worte zur Isolationsstufe

Das zweimalige Auswerten der Unterabfrage kann ein weiteres Problem verursachen. Abhängig von der Isolationsstufe Ihrer Abfrage kann das Ergebnis der ersten Auswertung in einer Umgebung mit mehreren Benutzern von der zweiten abweichen. Es ist verrückt.

Um sicherzustellen, dass stabile Ergebnisse zurückgegeben werden, können Sie versuchen, eine SNAPSHOT ISOLATION zu verwenden. Sie können auch ISNULL verwenden. Oder es kann ein Teile-und-Herrsche-Ansatz sein, wie oben erwähnt.

Imbiss

Also, was ist das Wesentliche?

  • Überprüfen Sie immer die logischen Lesevorgänge. Es zählt mehr als die verstrichene Zeit. Verwenden Sie die verstrichene Zeit und nehmen Sie Ihren Verstand weg. Ihre Maschine und der Produktionsserver werden immer unterschiedliche Ergebnisse haben. Gönnen Sie sich eine Pause.
  • Überprüfen Sie immer den Ausführungsplan, damit Sie wissen, was unter der Haube passiert.
  • Beachten Sie, dass bei der Übersetzung von COALESCE in CASE die Ausdrücke zweimal ausgewertet werden. Dann kann eine Unterabfrage oder ähnliches ein Problem sein. Das Zuweisen des Unterabfrageergebnisses zu einer Variablen vor der Verwendung in COALESCE kann eine Lösung sein.
  • Was schneller ist, hängt von den Ergebnissen und Ausführungsplänen der logischen Lesevorgänge ab. Es gibt keine allgemeine Regel, um festzustellen, ob COALESCE oder ISNULL schneller ist. Andernfalls könnte Microsoft darüber informieren, wie sie es in HierarchyID und SQL Graph getan haben.

Letztendlich kommt es wirklich darauf an.

Schlussfolgerung

Ich hoffe, Sie hatten eine lohnende Lektüre dieses Artikels. Hier sind die Punkte, die wir besprochen haben:

  • COALESCE ist eine der Möglichkeiten, mit Nullen umzugehen. Es ist ein Sicherheitsnetz, um Fehler im Code zu vermeiden.
  • Es akzeptiert die Argumentliste und gibt den ersten Nicht-Nullwert zurück.
  • Er wird während der Abfrageverarbeitung in einen CASE-Ausdruck konvertiert, verlangsamt die Abfrage jedoch nicht.
  • Obwohl es einige Ähnlichkeiten mit ISNULL gibt, gibt es 7 bemerkenswerte Unterschiede dazu.
  • Es kann mit der WHERE-Klausel verwendet werden.
  • Schließlich ist es nicht schneller oder langsamer als ISNULL.

Wenn Ihnen dieser Beitrag gefällt, warten die Social-Media-Buttons auf Ihren Klick. Teilen ist fürsorglich.

Danke.

Lesen Sie auch

Effektiver Umgang mit NULL-Werten mit der SQL COALESCE-Funktion für Anfänger

Eine praktische Verwendung der SQL COALESCE-Funktion