Время ожидания запроса при выполнении из Интернета, но очень быстрое при выполнении из SSMS.
-
20-09-2019 - |
Вопрос
Я пытаюсь отладить источник тайм-аута SQL в веб-приложении, которое я поддерживаю.У меня есть исходный код C#, поэтому я точно знаю, какой код выполняется.Я отладил приложение вплоть до строки, выполняющей код SQL, время ожидания которого истекает, и наблюдаю за выполнением запроса в профилировщике SQL.
Когда этот запрос выполняется из Интернета, время ожидания истекает через 30 секунд.Однако когда я вырезаю/вставляю запрос точно так, как представлено в Profiler, помещаю его в SSMS и запускаю, он возвращается практически мгновенно.Я обнаружил проблему в том, что для ARITHABORT установлено значение OFF в соединении, которое использует Интернет (то есть, если я выключаю ARITHABORT в сеансе SSMS, он работает в течение длительного времени, а если я снова включаю его, он запускается очень быстро).Однако, читая описание АРИТАБОРТа, кажется, что оно неприменимо...Я делаю только простой SELECT, и НИКАКАЯ арифметика не выполняется вообще.только одно INNER JOIN с условием WHERE:
Почему ARITHABORT OFF может вызывать такое поведение в этом контексте?Можно ли как-нибудь изменить настройку ARITHABORT для этого соединения из SSMS?Я использую SQL Server 2008.
Решение
Итак, ваш код C# отправляет специальный SQL-запрос на SQL Server, используя какой метод?Рассматривали ли вы возможность использования хранимой процедуры?Это, вероятно, обеспечит одинаковую производительность (по крайней мере, в движке), независимо от того, кто это назвал.
Почему?Параметр ARITHABORT — это один из факторов, на который оптимизатор обращает внимание при определении способа выполнения запроса (точнее, для сопоставления плана).Возможно, план в кэше имеет те же настройки, что и SSMS, поэтому он использует кэшированный план, но с противоположным параметром ваш код C# вызывает перекомпиляцию (или, возможно, вы действительно сталкиваетесь с проблемой). ПЛОХОЙ план в кеше), что во многих случаях, безусловно, может снизить производительность.
Если вы уже вызываете хранимую процедуру (вы не отправляли свой запрос, хотя, думаю, вы это хотели), вы можете попробовать добавить OPTION (RECOMPILE) к проблемному запросу (или запросам) в хранимой процедуре.Это будет означать, что эти операторы всегда будут перекомпилироваться, но это может предотвратить использование плохого плана, который вы, похоже, выполняете.Другой вариант — убедиться, что при компиляции хранимой процедуры пакет выполняется с параметром SET ARITHABORT ON.
Наконец, вы, кажется, спрашиваете, как изменить настройку ARITHABORT в SSMS.Я думаю, вы хотели спросить, как принудительно включить настройку ARITHABORT в свой код.Если вы решите продолжить отправку специального SQL-запроса из вашего приложения C#, то, конечно, вы можете отправить команду в виде текста, состоящего из нескольких операторов, разделенных точкой с запятой, например:
SET ARITHABORT ON; SELECT ...
Дополнительную информацию о том, почему возникает эта проблема, можно найти в замечательной статье Эрланда Соммарскога:
Другие советы
Этот ответ включает способ решения этой проблемы:
При выполнении следующих команд от имени администратора в базе данных все запросы выполняются должным образом, независимо от настройки ARITHABORT.
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
Обновлять
Кажется, что у большинства людей эта проблема возникает очень редко, и описанный выше метод является достойным одноразовым решением.Но если конкретный запрос обнаруживает эту проблему более одного раза, более долгосрочным решением этой проблемы было бы использование подсказок запроса, таких как OPTIMIZE FOR
и OPTION(Recompile)
, как описано в Эта статья.
У меня уже много раз возникала эта проблема, но если у вас есть хранимая процедура с той же проблемой, удаление и воссоздание хранимой процедуры решит проблему.
Это называется прослушиванием параметров.Вам необходимо всегда локализовать параметры в хранимой процедуре, чтобы избежать этой проблемы в будущем.
Я понимаю, что это может быть не то, чего хочет оригинальный автор, но может помочь кому-то с той же проблемой.
Если вы используете Entity Framework, вы должны знать, что параметры запроса для строковых значений по умолчанию отправляются в базу данных как nvarchar. Если сравниваемый столбец базы данных имеет тип varchar, в зависимости от ваших параметров сортировки план выполнения запроса может потребовать шага «IMPLICIT CONVERSION», который принудительно выполнить полное сканирование.Я мог бы подтвердить это, посмотрев в мониторинге базы данных опцию дорогих запросов, которая отображает план выполнения.
Наконец, объяснение такого поведения в этой статье:https://www.sqlskills.com/blogs/jonathan/implicit-conversions-that-cause-index-scans/
У меня была та же проблема, и она была исправлена путем выполнения процедуры «ПЕРЕКОМПИЛЬ».Вы также можете попробовать использовать анализ параметров.Моя проблема была связана с кешем SQL.
Если вы можете изменить свой код, чтобы исправить прослушивание параметров, оптимизация для неизвестной подсказки — ваш лучший вариант.Если вы не можете изменить свой код, лучшим вариантом является exec sp_recompile «имя процесса», который заставит только этот сохраненный процесс получить новый план выполнения.Удаление и повторное создание процесса будет иметь аналогичный эффект, но может привести к ошибкам, если кто-то попытается выполнить процесс, пока вы его удалили.DBCC FREEPROCCACHE удаляет все ваши кэшированные планы, которые могут разрушить вашу систему, вплоть до множества тайм-аутов в производственной среде с тяжелыми транзакциями.Установка arithabort не является решением проблемы, но является полезным инструментом для определения того, является ли проблема перехватом параметров.
У меня та же проблема: при попытке позвонить по SP из SMSS это заняло 2 секунды, а из веб-приложения (ASP.NET) — около 3 минут.
Я попробовал все предложенные решения sp_recompile
, DBCC FREEPROCCACHE
и DBCC DROPCLEANBUFFERS
но ничто не решило мою проблему, но когда я попробовал обнюхивать параметры, это помогло и сработало нормально.