Сохраненная процедура медленнее при вызове из ASP.NET или SQL Mgmt Admin

Мы пытаемся диагностировать медленность в сложной хранимой процедуре (у нее есть несколько огромных запросов).

Когда мы вызываем SP из ASP.NET, это занимает 5 секунд.

Когда мы вызываем его из SQL Management Studio (только с помощью EXEC), он занимает 0,05 секунды.

Мы тестировали это поведение последовательно разными способами и обстоятельствами.

Это с С#.NET. База данных - это MS SQL Server 2012.

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

1) Мы вычисляем прошедшее время в консольном приложении С#.NET следующим образом:

stopwatch.Start();
rdr = cmd.ExecuteReader();
stopwatch.Stop();

2) Мы вычисляем прошедшее время в процедуре SQL, вызывая GETDATE() до и после запроса, а затем сохраняя это время в маленькой таблице. Мы можем запросить эту таблицу в SQL Mgmt Studio, чтобы узнать, как долго выполнялись запросы внутри SP.

Таким образом, мы можем видеть, сколько времени потрачено на SQL в сравнении с целым, а 99% этого потрачено на SQL.

Но трудно отлаживать и улучшать, если он не замедляется и в SQL Mgmt Studio.

Итак, мой вопрос в том, почему разница? Может быть, SQL Mgmt Studio блокируется иначе, чем консольное приложение?

Ответ 1

Такое поведение часто связано с тем, что вы получаете разные планы выполнения от ADO.NET и SSMS. Это потому, что план выполнения должен учитывать не только сам SQL, но и контекст в виде ANSI_NULLS, ARITHABORT и нескольких других параметров. Таким образом, если эти параметры не совпадают, план выполнения из одной среды не может использоваться в другом.

При настройках по умолчанию все одинаково в SSMS и ADO.NET, кроме ARITHABORT. Это значение отключено в ADO.NET и включено в SSMS, поэтому, чтобы получить тот же план кеширования запросов, что и ваше приложение, вам необходимо установить ARITHABORT OFF в SSMS. Теперь вы должны увидеть ту же производительность в SSMS, что и при вызове приложения. Смотрите дополнительную информацию в этом хорошем сообщении в блоге: http://www.sommarskog.se/query-plan-mysteries.html

Если ваш запрос возвращает много данных, есть еще один фактор, потому что по умолчанию SSMS считывает все эти данные и отображает их перед завершением и отображением общего времени запроса. Как быстро читается, это зависит от того, где вы выполняете SSMS, локально на сервере или удаленном компьютере. В случае удаленного доступа данные должны передаваться по сети, что обычно медленнее, чем локальный. Обычно измерение времени передачи в порядке, потому что ваше приложение делает то же самое. Однако SSMS также отображает данные, и это может занять намного больше времени, чем загрузка. Чтобы этого избежать, вы можете отключить отображение данных в SSMS с помощью "Инструменты- > Параметры- > Результаты запросов- > SQL-Server- > Результаты для Grid- > Discard результатов после выполнения".

Если вы по-прежнему получаете другое поведение, запишите планы выполнения через SQL Profiler и сравните их.

Ответ 2

У меня была аналогичная проблема в прошлом году. Попробуйте включить arithabort в хранимой процедуре: SET ARITHABORT ON

Выдержка из msdn

Параметр ARITHABORT по умолчанию для SQL Server Management Studio включен. Настройка клиентских приложений ARITHABORT на OFF может принимать разные планы запросов, что затрудняет устранение неполадок, связанных с плохой работой. То есть, один и тот же запрос может быстро выполняться в студиях управления, но медленнее в приложении. Когда поиск и устранение неполадок с помощью Management Studio всегда соответствуют настройке клиента ARITHABORT.