У меня есть хранимая процедура, которая использует курсор FAST_FORWARD для хронологического цикла над набором записей ~ 300 000 и присваивает их наборам объявлений на основе состояния множества запущенных переменных и флаги, частично реализованные в виде переменных таблицы. Я много думал о том, как сделать это на основе набора, и я просто не могу этого сделать. Поэтому я придерживаюсь подхода курсора и мне нужно оптимизировать этот код.Сохраненная процедура с курсорным контуром FAST_FORWARD начинается быстро, заканчивается медленно
Я заметил, что первые 10% прогресса загружаются и обрабатываются очень быстро (2000 строк/сек), около 20% прогресса замедляется примерно до 300 строк в секунду, и в конце он замедляется до 60 строк/сек.
ИМО это может быть из-за 4 причины:
- Курсор замедлится, который я думаю, вряд ли с FAST_FORWARD курсором
- Обработка замедляющий. Для моих «групп» я использую переменные таблицы, в которые я вставляю, обновляю и удаляю. В любой момент времени макс. около 10 строк в этих переменных.
- Вставка в таблицы целей замедляется. Я не понимаю, почему это было бы, у меня нет триггеров, определенных на них, и они просто обычные таблицы.
- Зла магия
Либо это, либо мой процент счетчик сломан:
SET @curprogress = @curprogress + 1
IF (@curprogress - ((@totprogress/100) * (FLOOR(@curprogress * 100/@totprogress)))) BETWEEN 0 AND 1 BEGIN
SET @msg = CAST(FLOOR(@curprogress * 100/@totprogress) AS VARCHAR)
RAISERROR('%s%s', 0, 1, @msg, '%...') WITH NOWAIT;
END
Кто-нибудь какой-нибудь ключ к разгадке, что искать и как идти по ускорению этого запроса?
Символическое отрывок из моего кода:
WHILE....
-- Fetch new record to be assigned to one of the open declaration sets
FETCH NEXT INTO @row_field1, @row_field2....
IF (@flag2 = 1) AND ((@flag1 = 0) OR (@row_field1 <> @prevrow_field1))
BEGIN
-- Logging info: we are closing a child declaration set
INSERT INTO @logtable SELECT '--> LOG MESSAGE'
INSERT INTO @logtable
SELECT format_message(@row_field1, @calc_field2, field3...)
FROM @runningtable_sub S LEFT JOIN @runningtable_main M ON S.MainID = M.ID
-- Update enddate of parent
UPDATE M SET M.enddate = DATEADD(day,365,S.enddate)
FROM @runningtable_sub S
LEFT JOIN @runningtable_main M
ON S.MainID = M.ID
-- close and save child
INSERT INTO outputtable_main
SELECT @field1, COALESCE(Z.Field1,'NULL'), S.startdate, S.enddate,
M.Startdate, M.Enddate
FROM @runningtable_sub S
LEFT JOIN @runningtable_main M ON S.MainID = M.ID
-- delete child from running table
DELETE FROM @runningtable_sub WHERE S.enddate < @curdate
END
Я не могу опубликовать весь код, постараюсь больше разместить сообщение. Основная таблица очищается в другом месте. Я вставляю между 0-3 строк за проход. Являются ли обновления и удаления слишком дорогостоящими для переменных таблицы? Курсор находится в режиме просмотра, который обычно загружается через 10-16 секунд. Я изменил курсор на переменную таблицы и цикл WHILE, но никаких изменений. Поэтому проблема должна быть где-то в теле. – thomaspaulb
Это оказалось «ОБНОВЛЕНИЕ ОТ ..LEFT JOIN', используя ваше временное оборудование. Он также идет медленнее с каждой строкой. Странно, что проблема теперь исчезла сама по себе, хотя я не сделал никаких заметных изменений в СП. Я в недоумении, но я переписал процедуру с помощью сгруппированного ввода, поэтому мне больше не нужно использовать рабочие таблицы, но работать с работающими переменными. Это намного быстрее само по себе, и никаких утверждений 'UPDATE' больше нет. Я приму свой ответ за битку приборов. – thomaspaulb