2013-06-27 5 views
1

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

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 минут!

Любая идея, почему?

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

ОБНОВЛЕНИЕ Некоторые статистики ожиданий.

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

+3

ли вы измеряете какие статы подождать и посмотреть, что занимает 13 минут? Может быть автозагрузкой журнала, файла данных tempdb, блокировки, кто знает? –

+0

@AaronBertrand Не совсем уверен, как это сделать, я не администратор базы данных и мало опыта в оптимизации –

+0

Вы [можете найти это полезное чтение] (http://www.sqlperformance.com/2013/03/io-subsystem/кусок удаляет). Или кто-то, кого вы нанимаете, у кого есть опыт в оптимизации. :-) Вы пытались использовать транзакции внутри цикла? –

ответ

3

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

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

+0

Результаты также вставляются в таблицу temp, мне еще нужно предварительно развить основную БД? Также, какой рекомендуемый размер temp db? Первоначально это было 200 Мб, я увеличил его до 500 Мб, но не вижу никаких заметных результатов. –

+0

Если основная БД испытывает события авторазработки, то да. Рекомендуемый размер tempdb - «это зависит», увы. Я сравниваю мины под типичной нагрузкой и устанавливаю ее на разумное число для загрузки моего сервера при запуске. (Tempdb растет под нагрузкой, но при запуске возвращается к исходному указанному размеру.) Эта статья об оптимизации tempdb может помочь. http://msdn.microsoft.com/en-us/library/ms175527%28v=sql.105%29.aspx –

+0

К сожалению, это не помогло. Я удвоил по размеру как TempDB основной БД, и это не повлияло на скорость.В большинстве случаев «PAGEIOLATCH_SH» ждет очень мало 20-50 мс, может ли это иметь такой огромный эффект при задержке или это что-то еще? –