Was ist der effizienteste Weg, um zwei große Ergebnismengen in SQL Server 2012 zu vergleichen?

9

Aktuelle Ratschläge für den effizientesten Weg zum Vergleich zweier großer Ergebnis- / Zeilensätze scheinen darin zu bestehen, den EXCEPTOperator zu verwenden. Dieses eigenständige SQL-Skript wird mit zunehmender Zeilengröße sehr ineffizient (@last-Werte ändern). Ich habe versucht, eindeutige Einträge in einer kombinierten Tabelle zu finden, aber ohne Verbesserung.

DECLARE @first AS INT, @step AS INT, @last AS INT; 

-- This script is comparing two record sets using EXCEPT
-- I want to find additions from OLD to NEW
-- As number of rows increase performance gets terrible
-- I don't have to use two tables. I could use one combined table but I want the same result as quickly as possible

-- Compare 100 to 110 rows - 0 seconds
-- Compare 1000 to 1010 rows - 1 seconds
-- Compare 10000 to 10010 rows - 16 seconds
-- Compare 100000 to 100010 rows - ABORT after 8 minutes (tables are populated in 18 seconds)

DECLARE @temptableOLD TABLE ([Result1] int);
SET @step = 1;  SET @first = 1; SET @last = 100000
WHILE(@first <= @last) BEGIN INSERT INTO @temptableOLD VALUES(@first) SET @first += @step END

DECLARE @temptableNEW TABLE ([Result1] int);
SET @step = 1;  SET @first = 1; SET @last = 100010
WHILE(@first <= @last) BEGIN INSERT INTO @temptableNEW VALUES(@first) SET @first += @step END

select * from @temptableNEW
except
select * from @temptableOLD
Will Healey
quelle

Antworten:

8

EXCEPT impliziert a DISTINCT Operation.

ich würde ... benutzen NOT EXISTS wenn dies nicht wirklich erforderlich ist.

Das Problem, das Sie haben, ist jedoch wahrscheinlich, dass Sie aufgrund der schlechten Kardinalitätsschätzungen, die mit Tabellenvariablen verbunden sind, verschachtelte Schleifen in einer nicht indizierten Tabelle erhalten.

select * from @temptableNEW
except
select * from @temptableOLD
OPTION (RECOMPILE)

Kann berücksichtigen, dass die Tabellen jeweils 100.000 Zeilen haben und einen anderen Plan angeben.

In SQL Server 2012 können Sie Tabellenvariablen nur über Einschränkungen Indizes hinzufügen. Wenn die Werte eindeutig sind, können Sie sie verwenden

DECLARE @temptableOLD TABLE ([Result1] int UNIQUE CLUSTERED);

um einen Index hinzuzufügen. Wenn dies für beide Tabellen durchgeführt wird, verwendet der Plan (nachdem der Hinweis zum erneuten Kompilieren hinzugefügt wurde) wahrscheinlich stattdessen einen Zusammenführungs-Join. Ohne Indizes würde ich einen Hash-Join erwarten.

Martin Smith
quelle
Danke Martin. Das ist die Antwort. OPTION (RECOMPILE) hat geholfen (100.000 in 5 Minuten), aber UNIQUE CLUSTERED auf beiden Tischen hat die große Verbesserung gebracht (100.000 in 7 Sekunden !!!). Ich habe diese Tabellen nur erstellt, um ein reales Problem zu demonstrieren, bei dem ich keine Kontrolle über die Tabellenindizierung auf zwei verschiedenen SQL-Servern habe, aber ich werde es über solche Tabellenvariablen verwalten.
Will Healey
4
@ WillHealey- #tempTabellen haben viele Vorteile gegenüber Tabellenvariablen (Statistik, Parallelität, flexiblere Indizierung). Wenn Sie dies also nicht in einem Kontext verwenden, in dem Sie auf Tabellenvariablen beschränkt sind, können Sie diese auch ausprobieren.
Martin Smith