Медленная хранимая процедура при вызове из Интернета, быстрая из Management Studio - PullRequest
92 голосов
/ 05 июля 2011

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

Я запустил Sql Profiler, отследил вызовы, которые истекли, и, наконец, обнаружил следующие вещи:

  1. Когда выполняются операторы из MS SQL Management Studio с теми же аргументами (фактически я скопировал вызов процедуры из трассировки профиля sql и запустил его): он завершается через 5 ~ 6 секунд.
  2. Но при вызове из веб-приложения это занимает более 30 секунд (в трассировке), поэтому моя веб-страница к тому времени истекает.

Помимо того, что у моего веб-приложения есть свой пользователь, все одинаково (та же база данных, соединение, сервер и т. Д.) Я также попытался выполнить запрос непосредственно в студии с пользователем веб-приложения, и это заняло не более 6 секунд.

Как мне узнать, что происходит?

Я предполагаю, что это не имеет никакого отношения к тому факту, что мы используем слои BLL> DAL или адаптеры таблиц, поскольку трассировка четко показывает, что задержка в реальной процедуре. Это все, что я могу придумать.

РЕДАКТИРОВАТЬ Я обнаружил в по этой ссылке , что ADO.NET устанавливает ARITHABORT в true - что хорошо в большинстве случаев, но иногда это происходит, и предлагаемая работа -around - добавить опцию with recompile в сохраненный процесс. В моем случае это не работает, но я подозреваю, что это очень похоже на это. Кто-нибудь знает, что еще ADO.NET делает или где я могу найти спецификацию?

Ответы [ 6 ]

74 голосов
/ 05 июля 2011

В прошлом у меня возникала похожая проблема, поэтому мне не терпится найти решение этого вопроса.Комментарий Аарона Бертранда по поводу OP привел к истечению времени ожидания при выполнении из Интернета, но сверхбыстрому при выполнении из SSMS , и хотя вопрос не является дубликатом, ответ вполне может относиться к вашей ситуации.

По сути, похоже, что SQL Server может иметь поврежденный кэшированный план выполнения.Вы используете неверный план на своем веб-сервере, но SSMS использует другой план, поскольку для флага ARITHABORT установлены другие параметры (которые в противном случае не повлияли бы на ваш конкретный запрос / хранимый процесс).

См. ADO.NET, вызывающая хранимую процедуру T-SQL, вызывает исключение SqlTimeoutException для другого примера с более полным объяснением и разрешением.

45 голосов
/ 11 декабря 2012

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

Исправление для меня состояло в том, чтобы изменить все параметры, которые используются в sproc, на локальные переменные.

например. изменить:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
SELECT * FROM Table WHERE ID = @param1 

до:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
DECLARE @param1a int
SET @param1a = @param1
SELECT * FROM Table WHERE ID = @param1a

Кажется странным, но это исправило мою проблему.

7 голосов
/ 06 сентября 2016

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

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

В конечном итоге было увеличено количество SP, время ожидания которых истекло, многие из которых никогда не делали этого раньше, с использованием DBCC DROPCLEANBUFFERS и DBBC FREEPROCCACHE частота инцидентов резко упалазначительно - все еще есть отдельные случаи, некоторые, где я подозреваю, что регенерация плана занимает некоторое время, а некоторые, где SP действительно недовыполнены и нуждаются в повторной оценке.

4 голосов
/ 05 июля 2011

Может ли быть так, что некоторые другие вызовы БД, сделанные до того, как веб-приложение вызывает SP, оставляют транзакцию открытой?Это может быть причиной для этого SP ждать при вызове веб-приложения.Я говорю, изолируйте вызов в веб-приложении (поместите его на новую страницу), чтобы убедиться, что некоторые предыдущие действия в веб-приложении вызывают эту проблему.

1 голос
/ 12 августа 2016

как @Zane сказал, что это может быть из-за перехвата параметров. Я испытал такое же поведение, и я взглянул на план выполнения процедуры и все операторы sp подряд (скопировал все операторы из процедуры, объявил параметры как переменные и присвоил переменным те же значения, что и параметры были). Однако план выполнения выглядел совершенно иначе. Выполнение sp заняло 3-4 секунды, и операторы подряд с одинаковыми значениями были немедленно возвращены.

executionplan

После некоторого поиска в Google я нашел интересное прочтение об этом поведении: Медленно в приложении, быстро в SSMS?

При компиляции процедуры SQL Server не знает, что значение @fromdate изменяется, но компилирует процедуру в предположении, что @fromdate имеет значение NULL. Поскольку все сравнения с NULL приводят к UNKNOWN, запрос вообще не может возвращать никаких строк, если @fromdate по-прежнему имеет это значение во время выполнения. Если SQL Server примет входное значение в качестве окончательной истины, он может построить план только с постоянным сканированием, которое вообще не обращается к таблице (выполните запрос SELECT * FROM Orders WHERE OrderDate> NULL, чтобы увидеть пример этого) , Но SQL Server должен генерировать план, который возвращает правильный результат независимо от того, какое значение имеет @fromdate во время выполнения. С другой стороны, нет необходимости строить план, который является наилучшим для всех ценностей. Таким образом, поскольку предполагается, что строки не будут возвращены, SQL Server выполняет поиск индекса.

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

create procedure dbo.procedure
    @dateTo datetime = null
begin
    if (@dateTo is null)
    begin
        select @dateTo  = GETUTCDATE()
    end

    select foo
    from dbo.table
    where createdDate < @dateTo
end

После того, как я изменил его на

create procedure dbo.procedure
    @dateTo datetime = null
begin
    declare @to datetime = coalesce(@dateTo, getutcdate())

    select foo
    from dbo.table
    where createdDate < @to
end 

это снова сработало как шарм.

1 голос
/ 15 мая 2016

Простая перекомпиляция хранимой процедуры (табличная функция в моем случае) работала для меня

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