MS SQL Server 2005 — самопроизвольно прерывается хранимая процедура

Клиент сообщил о повторяющихся случаях очень странного поведения при выполнении хранимой процедуры.

У них есть код, который запускает кешированную транспозицию изменчивого набора данных. Сохраненная процедура была написана для повторной обработки набора данных по запросу, если:
1. Набор данных изменился с момента последней повторной обработки
2. Набор данных не изменился в течение 5 минут.

(Второе условие останавливает массовый повторный пересчет во время изменений.)


Это работало нормально в течение пары недель, SP требовалось 1-2 секунды для завершения повторной обработки, и он делал это только тогда, когда это требовалось. Потом...

  • SP внезапно «перестал работать» (он просто продолжал работать и больше не возвращался)
  • Мы тонко изменили SP, и он снова заработал.
  • Через несколько дней снова перестал работать
  • Затем кто-то сказал: «Мы уже видели это раньше, просто перекомпилируйте SP».
  • Без изменений в коде мы перекомпилировали SP, и он заработал.
  • Через несколько дней снова перестал работать


Сейчас это повторилось много-много раз. SP внезапно «перестает работать», никогда не возвращается, и время ожидания клиента истекает. (Мы попытались запустить его через студию управления и отменили запрос через 15 минут.)

Однако каждый раз, когда мы перекомпилируем SP, он снова начинает работать.

Я еще не пробовал WITH RECOMPILE с соответствующими операторами EXEC, но я не особо хочу этого делать. Он вызывается сотни раз в час и обычно ничего не делает (он только обрабатывает данные несколько раз в день). Если возможно, я хочу избежать накладных расходов на перекомпиляцию того, что является относительно сложным SP, «просто чтобы избежать того, что «не должно» происходить...


  • Кто-нибудь испытал это раньше?
  • Есть ли у кого-нибудь предложения, как это побороть?


С уважением,
Дем.


ИЗМЕНИТЬ:

Псевдокод будет следующим:

  • читать "а" из table_x
  • читать "b" из table_x
  • Если (a ‹ b) вернуть
  • НАЧАТЬ СДЕЛКУ
  • УДАЛИТЬ table_y
  • INSERT INTO table_y ‹3 выбирает объединенные вместе>
  • ОБНОВЛЕНИЕ table_x
  • СОВЕРШИТЬ ТРАНЗАКЦИЮ

Выборы «некрасивые», но когда они выполняются в строке, они выполняются в кратчайшие сроки. В том числе, когда ИП отказывается выполняться. И профилировщик показывает, что это INSERT, на котором SP «зависает».

У SP нет параметров, и sp_lock ничего не показывает, что блокирует процесс.


person MatBailie    schedule 18.06.2009    source источник
comment
Мне кажется, что у вас есть транзакция, которая не фиксируется и не откатывается. Трудно сказать, не видя кода.   -  person Juliet    schedule 19.06.2009
comment
Да, и никогда не помешает загрузить последние пакеты обновления и обновления.   -  person Juliet    schedule 19.06.2009
comment
Это должен быть ЗАМОК, или, по крайней мере, ведет себя так...   -  person tekBlues    schedule 19.06.2009
comment
наш клиент передал все ИТ на аутсорсинг IBM. Они только исправляют то, что и когда им хочется.   -  person MatBailie    schedule 19.06.2009
comment
слишком случайно, что сразу после повторного запуска оператора ALTER он работает отлично. Кроме того, sp_lock не обнаружил ничего подходящего. (Ну, sp_lock3 скопирован с чьего-то сайта)   -  person MatBailie    schedule 19.06.2009
comment
у него определенно кэширован плохой план выполнения.   -  person Cade Roux    schedule 19.06.2009
comment
Было бы очень полезно увидеть этот оператор INSERT с 3 объединенными выборками.   -  person RBarryYoung    schedule 19.06.2009
comment
кто-нибудь ВЫБИРАЕТ данные, пока вы пытаетесь сделать это массовое обновление?   -  person KM.    schedule 19.06.2009


Ответы (8)


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

WITH RECOMPILE, вероятно, будет самым быстрым решением - используйте SET STATISTICS TIME ON, чтобы узнать, какова на самом деле стоимость перекомпиляции, прежде чем отбрасывать ее из-под контроля.

Если это все еще неприемлемое решение, возможно, лучший вариант — попытаться реорганизовать оператор вставки.

Вы не говорите, используете ли вы UNION или UNION ALL в своем операторе вставки. Я видел, как INSERT INTO с UNION создавали странные планы запросов, особенно в версиях SQL 2005 до SP2.

  • Предложение Раджа удалить и воссоздать целевую таблицу с помощью SELECT INTO — один из способов.

  • Вы также можете попробовать выбрать каждый из трех исходных запросов в свою собственную временную таблицу, а затем UNION эти временные таблицы вместе во вставке.

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

Я видел, как все эти подходы решают проблемы с производительностью в аналогичных сценариях; тестирование покажет, что дает наилучшие результаты с имеющимися у вас данными.

person Ed Harper    schedule 19.06.2009

Это след перехвата параметров. Да, первый шаг - попробовать RECOMPILE, хотя это не всегда работает так, как вы хотите, в 2005.

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

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

person RBarryYoung    schedule 18.06.2009
comment
К сожалению, параметров нет. Единственной переменной является содержимое обрабатываемого исходного набора данных. - person MatBailie; 19.06.2009

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

Вы также можете использовать WITH RECOMPILE, если набор меняется, но план запроса больше не годится.

В SQL Server 2008 вы можете использовать функцию OPTIMIZE FOR UNKNOWN.

Кроме того, если ваш процесс включает в себя заполнение таблицы и последующее использование этой таблицы в другой операции, я рекомендую разбить процесс на отдельные SP и называть их по отдельности WITH RECOMPILE. Я думаю, что планы, сгенерированные в начале процесса, иногда могут быть очень плохими (настолько плохими, что их нельзя завершить), когда вы заполняете таблицу, а затем используете результаты этой таблицы для выполнения операции. Потому что во время первоначального плана таблица сильно отличалась от той, что была после первоначальной вставки.

person Cade Roux    schedule 18.06.2009
comment
Нет параметров и изменения в наборе данных тонкие, не значительные. План выполнения вообще не должен меняться. Что делает это таким запутанным. Это как если бы план выполнения изменился, когда он не должен, как испорченная статистика. но мы проверили и их! вздох - person MatBailie; 19.06.2009
comment
Я добавил несколько замечаний о длинных процессах, которые используют несколько таблиц для получения промежуточных результатов. - person Cade Roux; 19.06.2009
comment
В этом случае нет промежуточных шагов. Просто УДАЛЕНИЕ, затем ВСТАВКА, ОБНОВЛЕНИЕ, на которое ссылается псевдокод, просто вводит GetDate() в таблицу управления метаданными. - person MatBailie; 19.06.2009

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

Попробуйте зарегистрировать ход вашего SP, как описано здесь или здесь.

person devio    schedule 18.06.2009

Я бы согласился с ответом, данным выше в комментарии, это звучит как незакрытая транзакция, особенно если вы все еще можете запустить оператор выбора из анализатора запросов.

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

Когда ваш SP заблокируется, можете ли вы выполнить вставку в table_y?

person Paddy    schedule 19.06.2009
comment
Единственный код, который когда-либо записывает в эту таблицу, — это рассматриваемая SP. Поскольку код НАЧАЛО ТРАНЗАКЦИИ, УДАЛИТЬ ‹таблицу›, ВСТАВИТЬ В ‹таблицу›, ОБНОВИТЬ ‹таблицу мета_данных›, ЗАВЕРШИТЬ ТРАНЗАКЦИЮ, я не вижу, где может возникнуть описанный сценарий. Тем более, что sp_lock не показывает никаких конфликтов блокировок. - person MatBailie; 19.06.2009
comment
Просто из интереса - что произойдет, если эта процедура будет запущена дважды, пока первая процедура все еще выполняется? - person Paddy; 19.06.2009

У вас есть работа по обслуживанию индексов?

Актуальна ли ваша статистика? Один из способов узнать это — проверить предполагаемые и фактические планы запросов на наличие больших вариаций.

person Mitch Wheat    schedule 19.06.2009
comment
IBM владеет списком администраторов баз данных для всех экземпляров SQL SERVER наших клиентов. Индексы поддерживаются в ночном процессе. Мне нужно будет проверить ФАКТИЧЕСКИЕ и РАСЧЕТНЫЕ планы, когда они будут работать, а затем проверить РАСЧЕТНЫЕ планы, когда они «сломаны». Я не могу получить НАСТОЯЩУЮ информацию о том, когда он сломался, поскольку он, похоже, никогда не возвращается. И нет, мы не можем часами оставлять заблокированный стол в ожидании его повторной настройки на работающей системе :) - person MatBailie; 19.06.2009

Как уже говорили другие, весьма вероятно, что это незафиксированная транзакция.

Мое лучшее предположение:

Вы захотите убедиться, что table_y можно удалить полностью и быстро.

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

Еще одно замечание: попробуйте использовать truncate, если это возможно. он использует меньше ресурсов, чем удаление без предложения where:

truncate table table_y

Кроме того, если в вашей СОБСТВЕННОЙ транзакции произойдет ошибка, это приведет к тому, что все последующие вызовы (очевидно, каждые 5 минут) будут "зависать", если вы не обработаете свою ошибку:

begin tran
begin try
 -- do normal stuff
end try
begin catch
 rollback
end catch
commit

Самая первая ошибка - это то, что даст вам информацию о фактической ошибке. Видеть, как он зависает в ваших собственных последующих тестах, — это просто вторичный эффект.

person Jeff Meatball Yang    schedule 20.06.2009

Если вы делаете эти шаги:

DELETE table_y
INSERT INTO table_y <3 selects unioned together>

Возможно, вы захотите попробовать это вместо этого.

DROP TABLE table_y
SELECT INTO table_y <3 selects unioned together>
person Raj    schedule 19.06.2009
comment
Я думаю, вы имеете в виду TRUNCATE TABLE, а не DROP TABLE. Кроме того, контекст безопасности, вызывающий хранимую процедуру, не может ОБРЕЗАТЬ таблицу, работает только УДАЛЕНИЕ. Кроме того, проблема заключается во ВСТАВКЕ, а не в очистке данных. - person MatBailie; 19.06.2009
comment
Но тот факт, что данные меняются в середине пакета, означает, что план выполнения, выбранный в начале пакета, может быть плохим, поэтому я хочу получить лучшие планы выполнения по частям. - person Cade Roux; 19.06.2009