Was ist der Algorithmus hinter dem EXCEPT-Operator?

10

Was ist der interne Algorithmus für die Funktionsweise des Operators Except in SQL Server? Nimmt es intern einen Hash jeder Zeile und vergleicht es?

David Lozinksi führte eine Studie durch, SQL: Der schnellste Weg, neue Datensätze einzufügen, wo noch keiner existiert. Er zeigte, dass die Except-Anweisung für Zeilen mit großer Anzahl die schnellste ist. eng mit unseren Ergebnissen unten verbunden.

Annahme: Ich würde denken, dass der Link-Join am schnellsten ist, da er nur eine Spalte vergleicht. Außer würde am längsten dauern, da alle Spalten verglichen werden müssen.
Mit diesen Ergebnissen ist unser Denken jetzt Außer automatisch und nimmt intern einen Hash von jeder Zeile? Ich habe mir einen Ausführungsplan angesehen und er verwendet etwas Hash.

Hintergrund: Unser Team hat zwei Heap-Tabellen verglichen. Tabelle A Zeilen, die nicht in Tabelle B enthalten sind, wurden in Tabelle B eingefügt.

Die Heap-Tabellen (aus dem alten Textdateisystem) haben keine Primärschlüssel / Guids / Bezeichner. Einige der Tabellen hatten doppelte Zeilen, daher haben wir den Hash jeder Zeile gefunden, doppelte Zeilen entfernt und Primärschlüssel-IDs erstellt.

1) Zuerst haben wir eine Ausnahme-Anweisung ausgeführt, ohne (Hash-Spalte)

select * from TableA
Except
Select * from TableB,

2) Dann haben wir einen Link-Join-Vergleich zwischen den beiden Tabellen auf der HashRowId durchgeführt

select * 
FROM dbo.TableA A
left join dbo.TableB B
    on A.RowHash =  B.RowHash
where B.Hash is null

überraschenderweise war der Insert Statement Exert der schnellste.

Die Ergebnisse entsprechen tatsächlich den Testergebnissen von David Lozinksi

Geben Sie hier die Bildbeschreibung ein

Gemeinschaft
quelle
1
Das wird nicht immer der Fall sein. Ich habe zum Beispiel beim Lesen etwas andere Ergebnisse gefunden .
Aaron Bertrand

Antworten:

10

Was ist der interne Algorithmus für die Funktionsweise des Operators Except in SQL Server?

Ich würde nicht sagen, dass es einen speziellen internen Algorithmus für gibt EXCEPT. Für A EXCEPT Bnimmt der Motor unterschiedliche Tupel aus A und Subtraktionen Zeilen (falls erforderlich) , dass Spiel in B. Es gibt keinen speziellen Abfrage - Plan - Betreiber. Die Unterscheidung und die Subtraktion werden durch die typischen Operatoren implementiert, die Sie mit einer Sortierung oder einem Join sehen würden. Nested-Loop-Join, Merge-Join und Hash-Join werden unterstützt. Um dies zu zeigen, werfe ich 15 Millionen Zeilen in ein Paar Haufen:

DROP TABLE IF EXISTS dbo.TABLE_1;

CREATE TABLE dbo.TABLE_1 (
    COL1 BIGINT NULL,
    COL2 BIGINT NULL
);

INSERT INTO dbo.TABLE_1 WITH (TABLOCK)
SELECT TOP (15000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), NULL
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);


DROP TABLE IF EXISTS dbo.TABLE_2;

CREATE TABLE dbo.TABLE_2 (
    COL1 BIGINT NULL,
    COL2 BIGINT NULL
);

INSERT INTO dbo.TABLE_2 WITH (TABLOCK)
SELECT TOP (15000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), NULL
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

Das Optimierungsprogramm trifft die üblichen kostenbasierten Entscheidungen zur Implementierung der Sortierung und des Joins. Mit zwei Haufen bekomme ich wie erwartet einen Hash-Join. Sie können andere Verknüpfungstypen natürlich anzeigen, indem Sie Indizes hinzufügen oder die Daten in einer der beiden Tabellen ändern. Im Folgenden erzwinge ich Merge- und Loop-Verknüpfungen mit Hinweisen nur zur Veranschaulichung:

schließt sich an

Nimmt es intern einen Hash jeder Zeile und vergleicht es?

Nein, es wird wie jeder andere Join implementiert. Ein Unterschied besteht darin, dass NULL-Werte als gleich behandelt werden. Dies ist eine spezielle Art von Vergleich, die Sie im Ausführungsplan sehen können : <Compare CompareOp="IS">. Mit T-SQL können Sie jedoch denselben Plan erhalten, der das EXCEPTSchlüsselwort nicht enthält . Das Folgende hat beispielsweise genau den gleichen Abfrageplan wie die EXCEPTAbfrage, die einen Hash-Join verwendet:

SELECT t1.*
FROM
(
    SELECT DISTINCT COL1, COL2
    FROM dbo.TABLE_1
) t1
WHERE NOT EXISTS (
    SELECT 1
    FROM dbo.TABLE_2 t2
    WHERE (t1.COL1 = t2.COL1 OR (t1.COL1 IS NULL AND t2.COL1 IS NULL))
    AND (t1.COL2 = t2.COL2 OR (t1.COL2 IS NULL AND t2.COL2 IS NULL))
);

Wenn Sie das XML der Ausführungspläne unterscheiden, werden nur oberflächliche Unterschiede in Bezug auf Aliase und ähnliches angezeigt. Die Testreste für die Hash-Joins führen den Zeilenvergleich durch. Sie sind für beide Abfragen gleich:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie immer noch Zweifel haben, habe ich PerfView mit der höchsten verfügbaren Abtastrate ausgeführt, um Anrufstapel für die Abfrage mit EXCEPTund die Abfrage ohne zu erhalten. Hier sind die Ergebnisse nebeneinander:

Geben Sie hier die Bildbeschreibung ein

Es gibt keinen wirklichen Unterschied. Die Call-Stacks dort sind aufgrund der Hash-Übereinstimmungen im Plan vorhanden. Wenn ich Indizes hinzufüge, um einen natürlichen Zusammenführungs-Join zu erhalten, werden in den Aufrufstapeln keine Verweise auf Hashing angezeigt:

Geben Sie hier die Bildbeschreibung ein

Jedes auftretende Hashing ist auf die Implementierung von Hash-Match-Operatoren zurückzuführen. Es gibt nichts Besonderes, EXCEPTwas zu einem speziellen internen Hashing-Vergleich führt.

Joe Obbish
quelle