Какой самый эффективный способ сравнить два больших набора результатов в SQL Server 2012

9

В настоящее время совет по наиболее эффективному способу сравнения двух больших наборов результатов / строк заключается в использовании EXCEPTоператора. Этот автономный SQL-скрипт ниже становится очень неэффективным при увеличении размеров строк (изменение значений @last). Я пытался найти уникальные записи в комбинированной таблице, но без улучшений.

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
Уилл Хили
источник

Ответы:

8

EXCEPTподразумевает DISTINCTоперацию.

Я бы использовал, NOT EXISTSесли это на самом деле не требуется.

Однако проблема, с которой вы столкнулись, вероятно, заключается в том, что вы получаете вложенные циклы в неиндексированной таблице из-за плохой оценки количества элементов, связанной с табличными переменными.

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

Смогу учесть, что таблицы имеют по 100К строк и дают другой план.

В SQL Server 2012 вы можете добавлять индексы к табличным переменным только через ограничения. Если значения уникальны, вы можете использовать

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

добавить индекс. Если это сделано для обеих таблиц, план (после добавления подсказки о перекомпиляции), скорее всего, вместо этого будет использовать объединение слиянием. Без каких-либо индексов я бы ожидал хеш-соединения.

Мартин Смит
источник
Спасибо Мартин. Это ответ. OPTION (RECOMPILE) помог (100 000 за 5 минут), но UNIQUE CLUSTERED на обоих столах сделал большое улучшение (100 000 за 7 секунд !!!). Я создал эти таблицы только для демонстрации реальной проблемы, когда у меня нет контроля над индексированием таблиц на двух разных серверах SQL, но я буду управлять ими с помощью таких переменных таблицы.
Уилл Хили
4
#tempТаблицы @WillHealey имеют много преимуществ по сравнению с табличными переменными (статистика, параллелизм, более гибкое индексирование), поэтому, если вы не используете это в контексте, где вы ограничены переменными таблицы, вы можете попробовать и их.
Мартин Смит