Constant Scan-Spooling

14

Ich habe eine Tabelle mit ein paar Dutzend Zeilen. Es folgt eine vereinfachte Einrichtung

CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);

Und ich habe eine Abfrage, die diese Tabelle mit einer Reihe von Tabellenwert-erstellten Zeilen (bestehend aus Variablen und Konstanten) wie verknüpft

DECLARE @id1 int = 101, @id2 int = 105;

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (@id1, 'A'),
        (@id2, 'B')
    ) p([Id], [Code])
    FULL JOIN #data d ON d.[Id] = p.[Id];

Der Ausführungsplan für Abfragen zeigt, dass das Optimierungsprogramm eine FULL LOOP JOINStrategie verwendet, die angemessen erscheint, da beide Eingaben nur sehr wenige Zeilen enthalten. Eine Sache, die mir aufgefallen ist (und der ich nicht zustimmen kann), ist, dass TVC-Zeilen gespoolt werden (siehe Bereich des Ausführungsplans im roten Feld).

Constant Scan-Spooling

Warum führt der Optimierer hier die Spool ein, was ist der Grund dafür? Hinter der Spule steckt nichts Komplexes. Sieht aus wie es nicht notwendig ist. Wie kann man es in diesem Fall loswerden, was sind die möglichen Wege?


Der obige Plan wurde am erhalten

Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)

ich ein
quelle
Zugehöriger Vorschlag unter feedback.azure.com
i-one

Antworten:

19

Warum führt der Optimierer hier die Spool ein, was ist der Grund dafür? Hinter der Spule steckt nichts Komplexes.

Die Sache hinter dem Spool ist keine einfache Tabellenreferenz, die einfach dupliziert werden könnte, wenn die linke Join- / Antisemi- Join- Alternative generiert wird.

Es mag ein wenig wie eine Tabelle aussehen (Constant Scan), aber für den Optimierer * ist es eine UNION ALLder separaten Zeilen in der VALUESKlausel.

Die zusätzliche Komplexität reicht aus, damit der Optimierer die Quellzeilen spoolen und wiedergeben kann und die Spool später nicht durch ein einfaches "table get" ersetzt. Die anfängliche Umwandlung vom vollständigen Join sieht beispielsweise folgendermaßen aus:

früher Plan

Beachten Sie die zusätzlichen Spools, die durch die allgemeine Transformation eingeführt wurden. Spulen über einem einfachen Tisch werden später von der Regel aufgeräumt SpoolGetToGet.

Wenn das Optimierungsprogramm eine entsprechende SpoolConstGetToConstGetRegel hätte, könnte es im Prinzip so funktionieren, wie Sie möchten.

Wie kann man es in diesem Fall loswerden, was sind die möglichen Wege?

Verwenden Sie eine reale Tabelle (temporär oder variabel) oder schreiben Sie die Umwandlung von der vollständigen Verknüpfung manuell, zum Beispiel:

WITH 
    p([Id], [Code]) AS
    (
        SELECT @id1, 'A'
        UNION ALL
        SELECT @id2, 'B'
    ),
    FullJoin AS
    (
        SELECT
            p.Code,
            d.[Status]
        FROM p
        LEFT JOIN #data d 
            ON d.[Id] = p.[Id]
        UNION ALL
        SELECT
            NULL,
            D.[Status]
        FROM #data AS D
        WHERE NOT EXISTS
        (
            SELECT *
            FROM p
            WHERE p.Id = D.Id
        )
    )
SELECT
    COALESCE(FullJoin.Code, 'X') AS Code,
    COALESCE(FullJoin.Status, 0) AS [Status]
FROM FullJoin;

Plan für manuelles Umschreiben:

Manueller Plan zum Umschreiben

Dies hat geschätzte Kosten von 0,0067201 Einheiten, verglichen mit 0,0203412 Einheiten für das Original.


* Kann LogOp_UnionAllim konvertierten Baum (TF 8605) als beobachtet werden . Im Eingabebaum (TF 8606) ist es ein LogOp_ConstTableGet. Der konvertierte Baum zeigt den Baum der Ausdruckselemente des Optimierers nach dem Parsen, Normalisieren, Algebrisieren, Binden und einigen anderen vorbereitenden Arbeiten. Der Eingangsbaum zeigt die Elemente nach der Konvertierung in Negationsnormalform (NNF convert), Laufzeitkonstante kollabiert, und ein paar anderen Bits und Bob. Die NNF-Konvertierung beinhaltet unter anderem Logik, um logische Vereinigungen zu reduzieren und gemeinsame Tabellen zu erhalten.

Paul White Monica wieder einsetzen
quelle
3

Der Tabellenspool erstellt einfach eine Tabelle aus den beiden in der VALUESKlausel enthaltenen Tupelsätzen.

Sie können den Spool eliminieren, indem Sie diese Werte zuerst in eine temporäre Tabelle einfügen:

DROP TABLE IF EXISTS #data;
CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);

DROP TABLE IF EXISTS #p;
CREATE TABLE #p
(
    Id int NOT NULL
    , Code char(1) NOT NULL
);

DECLARE @id1 int = 101, @id2 int = 105;

INSERT INTO #p (Id, Code)
VALUES
        (@id1, 'A'),
        (@id2, 'B');


SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM #p p
    FULL JOIN #data d ON d.[Id] = p.[Id];

Wenn Sie sich den Ausführungsplan für Ihre Abfrage ansehen, sehen Sie, dass die Ausgabeliste zwei Spalten enthält, die das UnionPräfix verwenden. Dies ist ein Hinweis darauf, dass der Spool eine Tabelle aus einer unionsgeeigneten Quelle erstellt:

Bildbeschreibung hier eingeben

Das FULL OUTER JOINerfordert, dass SQL Server pzweimal auf die Werte zugreift, einmal für jede "Seite" des Joins. Durch das Erstellen einer Spool können die resultierenden inneren Schleifen auf die Spooldaten zugreifen.

Interessanterweise verwendet SQL Server keinen Spool , wenn Sie die Zeichen FULL OUTER JOINmit LEFT JOINund RIGHT JOINund UNIONdie Ergebnisse zusammen ersetzen .

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (101, 'A'),
        (105, 'B')
    ) p([Id], [Code])
    LEFT JOIN #data d ON d.[Id] = p.[Id]
UNION
SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (101, 'A'),
        (105, 'B')
    ) p([Id], [Code])
    RIGHT JOIN #data d ON d.[Id] = p.[Id];

Bildbeschreibung hier eingeben

Beachten Sie, dass ich nicht vorschlage, die UNIONobige Abfrage zu verwenden. Bei größeren Eingaben ist die Leistung möglicherweise nicht effizienter als die einfache, die FULL OUTER JOINSie bereits haben.

Max Vernon
quelle
Ist die Spule bei Ihrer tatsächlichen Arbeitsbelastung wirklich so teuer?
Max Vernon