Пакетная вставка TSQL - математика не работает

Мне нужно вставить 1,3 миллиона записей из одной таблицы в другую, и это занимает очень много времени (более 13 минут). После некоторых исследований я обнаружил, что эту операцию лучше выполнять в пакетном режиме, поэтому я собрал что-то вроде этого (фактический запрос сложнее, здесь он упрощен для краткости):

DECLARE @key INT; SET @key = 0; 
CREATE TABLE #CURRENT_KEYS(KEY INT)

WHILE 1=1
BEGIN
   -- Getting subset of keys
   INSERT INTO #CURRENT_KEYS(KEY)   
   SELECT TOP 100000 KEY FROM #ALL_KEYS WHERE KEY > @key
   IF @@ROWCOUNT = 0 BREAK

   -- Main Insert
   INSERT INTO #RESULT(KEY, VALUE)
   SELECT MAIN_TABLE.KEY, MAIN_TABLE.VALUE 
   FROM MAIN_TABLE INNER_JOIN #CURRENT_KEYS 
   ON MAIN_TABLE.KEY = #CURRENT_KEYS.KEY

   SELECT @key = MAX(KEY ) FROM #CURRENT_KEYS

   TRUNCATE TABLE #CURRENT_KEYS
END

У меня уже есть проиндексированный список из 1,3 миллиона ключей в таблице #ALL_KEYS, поэтому идея заключается в том, чтобы в цикле создать меньшее подмножество ключей для JOIN и INSERT. Приведенный выше цикл выполняется 13 раз (1 300 000 записей / 100 000 записей в пакете). Если поставить паузу всего через одну итерацию - время выполнения 9 секунд. Я предполагал, что общее время выполнения будет 9*13 секунд, но это те же самые 13 минут!

Есть идеи, почему?

ПРИМЕЧАНИЕ. Вместо временной таблицы #CURRENT_KEYS я попытался использовать CTE, но с тем же результатом.

ОБНОВЛЕНИЕ Немного статистики ожидания.

Я показываю для этого процесса PAGEIOLATCH_SH, а иногда и PREEMPTIVE_OS_WRITEFILEGATHER в статистике ожидания, иногда более 500 мс, но часто ‹ 100 мс. Также SP_WHO показывает пользователя как suspended на время запроса.


person Yuriy Galanter    schedule 27.06.2013    source источник
comment
Вы измеряли статистику ожидания и видели, что занимает 13 минут? Может ли быть автоматическое увеличение журнала, файл данных tempdb, блокировка, кто знает?   -  person Aaron Bertrand    schedule 27.06.2013
comment
@AaronBertrand Не совсем уверен, как это сделать, я не администратор баз данных и у меня мало опыта в оптимизации.   -  person Yuriy Galanter    schedule 27.06.2013
comment
Вы можете найти это полезным. Или кого-то, кого вы нанимаете, у кого есть опыт оптимизации. :-) Вы пробовали использовать транзакции внутри цикла?   -  person Aaron Bertrand    schedule 27.06.2013
comment
Спасибо посмотрю статью. Я попытался окружить внутреннюю вставку транзакцией, а также весь цикл - безрезультатно.   -  person Yuriy Galanter    schedule 27.06.2013
comment
Вопрос: Регистрируются ли вставки во временную таблицу?   -  person Yuriy Galanter    schedule 27.06.2013
comment
@AaronBertrand Я провел небольшое исследование статистики ожидания и обновил пост. Это полезно? Как я могу действовать в связи с этой находкой? Спасибо!   -  person Yuriy Galanter    schedule 28.06.2013


Ответы (1)


Я почти уверен, что вы испытываете давление на диск. PREEMPTIVE_OS_WRITEFILEGATHER — это событие автоматического роста (база данных становится больше), а PAGEIOLATCH_SH означает, что процесс ожидает фиксации буфера, который является запросом ввода-вывода (вероятно, событие роста вашего файла).

http://blog.sqlauthority.com/2011/02/19/sql-server-preemptive-and-non-preemptive-wait-type-day-19-of-28/

http://blog.sqlauthority.com/2011/02/09/sql-server-pageiolatch_dt-pageiolatch_ex-pageiolatch_kp-pageiolatch_sh-pageiolatch_up-wait-type-day-9-of-28/

Я бы порекомендовал предварительно увеличить как базу данных tempdb (для вашей временной таблицы), так и базу данных, которая будет содержать пакетную вставку.

http://support.microsoft.com/kb/2091024

person Katherine Villyard    schedule 27.06.2013
comment
Результаты также вставляются во временную таблицу, нужно ли мне предварительно увеличивать основную базу данных? Также каков рекомендуемый размер временной базы данных? Изначально это было 200 Мб, я увеличил его до 500 Мб, но не вижу заметных результатов. - person Yuriy Galanter; 28.06.2013
comment
Если основная БД испытывает события автороста, то да. Рекомендуемый размер tempdb зависит, увы. Я тестирую свой при типичной нагрузке и устанавливаю разумное число для нагрузки моего сервера при запуске. (База данных Tempdb увеличивается под нагрузкой, но при запуске возвращается к исходному заданному размеру.) Эта статья об оптимизации базы данных tempdb может помочь. msdn.microsoft.com/en-us/ библиотека/ms175527%28v=sql.105%29.aspx - person Katherine Villyard; 28.06.2013
comment
К сожалению, это не помогло. Я удвоил размер как TempDB, так и основной БД, и это не повлияло на скорость. В большинстве случаев PAGEIOLATCH_SH ожидание очень мало 20-50 мс, может ли оно все еще иметь такое огромное влияние на задержку или это что-то еще? - person Yuriy Galanter; 28.06.2013
comment
Файлы все еще растут? Возможно ли, что вставки перекрываются таким образом, что блокируют друг друга? - person Katherine Villyard; 28.06.2013
comment
Насколько я вижу, размеры файлов остаются такими же, как первоначальный размер - person Yuriy Galanter; 28.06.2013