MS SQL Server 2005 - хранимая процедура «самопроизвольно прерывается» - PullRequest
8 голосов
/ 19 июня 2009

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

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

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


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

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


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

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

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


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


Приветствия
Демс.


EDIT:

Псевдо-код будет выглядеть следующим образом:

  • читать "a" из таблицы_x
  • читать "b" из таблицы_x
  • Если (a НАЧАЛО СДЕЛКИ
  • УДАЛИТЬ table_y
  • INSERT INTO table_y <3 выбирает объединенные вместе>
  • ОБНОВЛЕНИЕ table_x
  • совершение транзакции

Селекты "не красивые", но при выполнении в строке они выполняются в кратчайшие сроки. В том числе, когда ИП отказывается завершать. А профилировщик показывает, что это ВСТАВКА, у которой ИП "глохнет"

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

Ответы [ 8 ]

3 голосов
/ 19 июня 2009

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

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

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

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

3 голосов
/ 19 июня 2009

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

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

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

1 голос
/ 19 июня 2009

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

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

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

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

  • Радж предлагает сбросить и воссоздание целевой таблицы с SELECT INTO это один из способов.

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

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

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

0 голосов
/ 20 июня 2009

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

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

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

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

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

truncate table table_y

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

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

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

0 голосов
/ 19 июня 2009

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

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

0 голосов
/ 19 июня 2009

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

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

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

0 голосов
/ 19 июня 2009

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

DELETE table_y
INSERT INTO table_y <3 selects unioned together>

Вы можете попробовать это вместо

DROP TABLE table_y
SELECT INTO table_y <3 selects unioned together>
0 голосов
/ 19 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...