Quel est le moyen le plus efficace pour comparer deux grands jeux de résultats dans SQL Server 2012

9

Le conseil actuel pour la manière la plus efficace de comparer deux grands ensembles de résultats / lignes semble être d'utiliser l' EXCEPTopérateur. Ce script SQL autonome ci-dessous devient très inefficace à mesure que la taille des lignes augmente (modifiez les valeurs @last). J'ai essayé de trouver des entrées uniques dans une table combinée mais sans amélioration.

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
la source

Réponses:

8

EXCEPTimplique une DISTINCTopération.

J'utiliserais NOT EXISTSsi ce n'est pas réellement requis.

Cependant, le problème que vous rencontrez est probable que vous obtenez des boucles imbriquées sur une table non indexée en raison des mauvaises estimations de cardinalité associées aux variables de table.

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

Pourra tenir compte du fait que les tables ont chacune 100 000 lignes et donner un plan différent.

Dans SQL Server 2012, vous pouvez uniquement ajouter des index aux variables de table via des contraintes. Si les valeurs sont uniques, vous pouvez utiliser

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

pour ajouter un index. Si cela est fait sur les deux tables, le plan (après l'ajout du conseil de recompilation) utilisera probablement une jointure de fusion à la place. Sans index, je m'attendrais à une jointure par hachage.

Martin Smith
la source
Merci Martin. Telle est la réponse. OPTION (RECOMPILE) a aidé (100 000 en 5 minutes), mais UNIQUE CLUSTERED sur les deux tables a fait la grosse amélioration (100 000 en 7 secondes !!!). J'ai uniquement créé ces tables pour illustrer un problème réel où je n'ai aucun contrôle sur l'indexation des tables sur deux serveurs SQL différents, mais je vais le gérer via de telles variables de table.
Will Healey
4
Les #temptables @WillHealey présentent de nombreux avantages par rapport aux variables de table (statistiques, parallélisme, indexation plus flexible), donc si vous ne l'utilisez pas dans un contexte où vous êtes limité aux variables de table, vous pouvez également les essayer.
Martin Smith