Qual é a maneira mais eficiente de comparar dois grandes conjuntos de resultados no SQL Server 2012

9

O conselho atual para a maneira mais eficiente de comparar dois grandes conjuntos de resultados / linhas parece ser o uso do EXCEPToperador. Este script SQL independente abaixo fica muito ineficiente à medida que os tamanhos das linhas aumentam (altere os últimos valores). Eu tentei encontrar entradas exclusivas em uma tabela combinada, mas sem melhorias.

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
fonte

Respostas:

8

EXCEPTimplica uma DISTINCToperação.

Eu usaria NOT EXISTSse isso não for realmente necessário.

No entanto, o problema que você está tendo é provável que esteja obtendo loops aninhados em uma tabela não indexada devido às estimativas de cardinalidade ruins associadas às variáveis ​​da tabela.

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

Será capaz de levar em conta que as tabelas têm 100 mil linhas cada e fornecer um plano diferente.

No SQL Server 2012, você pode adicionar índices apenas às variáveis ​​da tabela por meio de restrições. Se os valores forem únicos, você poderá usar

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

para adicionar um índice. Se feito nas duas tabelas, o plano (após a adição da dica de recompilação) provavelmente usará uma junção de mesclagem. Sem índices, eu esperaria uma junção de hash.

Martin Smith
fonte
Obrigado Martin. Essa é a resposta. OPTION (RECOMPILE) ajudou (100.000 em 5 minutos), mas UNIQUE CLUSTERED em ambas as tabelas fez a grande melhoria (100.000 em 7 segundos !!!). Eu apenas criei essas tabelas para demonstrar um problema da vida real em que não tenho controle sobre a indexação da tabela em dois servidores SQL diferentes, mas o gerirei através dessas variáveis ​​de tabela.
Will Healey
4
As #temptabelas do @WillHealey têm muitas vantagens sobre as variáveis ​​da tabela (estatísticas, paralelismo, indexação mais flexível); portanto, se você não estiver usando isso em um contexto em que está restrito às variáveis ​​da tabela, também poderá experimentá-las.
Martin Smith