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 B
nimmt 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:
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 EXCEPT
Schlüsselwort nicht enthält . Das Folgende hat beispielsweise genau den gleichen Abfrageplan wie die EXCEPT
Abfrage, 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:
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 EXCEPT
und die Abfrage ohne zu erhalten. Hier sind die Ergebnisse nebeneinander:
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:
Jedes auftretende Hashing ist auf die Implementierung von Hash-Match-Operatoren zurückzuführen. Es gibt nichts Besonderes, EXCEPT
was zu einem speziellen internen Hashing-Vergleich führt.