Jaki jest najbardziej efektywny sposób porównania dwóch dużych zestawów wyników w programie SQL Server 2012

9

Bieżącą radą dotyczącą najbardziej efektywnego sposobu porównywania dwóch dużych zestawów wyników / wierszy wydaje się być użycie EXCEPToperatora. Ten samodzielny skrypt SQL poniżej staje się bardzo nieefektywny wraz ze wzrostem rozmiarów wierszy (zmiana wartości @last). Próbowałem znaleźć unikalne wpisy w połączonej tabeli, ale bez poprawy.

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
źródło

Odpowiedzi:

8

EXCEPToznacza DISTINCToperację.

Użyłbym, NOT EXISTSjeśli nie jest to faktycznie wymagane.

Jednak problem, który masz, prawdopodobnie powoduje zagnieżdżenie pętli w nieindeksowanej tabeli ze względu na słabe oszacowania liczności związane ze zmiennymi tabeli.

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

Będzie mógł wziąć pod uwagę, że tabele mają 100 000 wierszy każdy i podać inny plan.

W SQL Server 2012 można dodawać indeksy do zmiennych tabeli tylko poprzez ograniczenia. Jeśli wartości są unikalne, możesz użyć

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

aby dodać indeks. Jeśli zostanie to wykonane w obu tabelach, plan (po dodaniu wskazówki dotyczącej ponownej kompilacji) prawdopodobnie zamiast tego użyje połączenia scalającego. Bez indeksów oczekiwałbym przyłączenia mieszającego.

Martin Smith
źródło
Dziękuję Martin. Oto odpowiedź. Pomogła OPCJA (RECOMPILE) (100 000 w 5 minut), ale WYJĄTKOWE ZESTAWIENIE na obu stołach znacznie poprawiło (100 000 w 7 sekund !!!). Te tabele utworzyłem tylko w celu zademonstrowania rzeczywistego problemu, w którym nie mam kontroli nad indeksowaniem tabel na dwóch różnych serwerach SQL, ale będę zarządzał nimi za pomocą takich zmiennych tabeli.
Will Healey,
4
#tempTabele @WillHealey mają wiele zalet w porównaniu ze zmiennymi tabelowymi (statystyki, równoległość, bardziej elastyczne indeksowanie), więc jeśli nie używasz tego w kontekście ograniczonym do zmiennych tabel, możesz również spróbować tych zmiennych.
Martin Smith