Почему запрос может длиться целую вечность, если выполняется через sp_executesql (через приложение) в отличие от обычного параметризованного запроса в SSMS?

#sql #sql-server #performance #tsql #timeout

#sql #sql-server #Производительность #tsql #тайм-аут

Вопрос:

Итак, у меня есть запрос, время от времени прерывающийся в приложении C # web api. Все начнется нормально, а затем в какой-то момент в будущем начнется тайм-аут и с этого момента тайм-аут истекает, если что-то не будет сделано.

Запрос создается с использованием Dapper, и когда я запускаю трассировку на сервере, я могу распознать запрос-нарушитель, в который он превратился. Если я запускаю это как есть на своем компьютере (он использует exec.sp_executesql N’the query’), на выполнение также уходит целая вечность. Я передаю его своему коллеге, и для него выполнение занимает всего 2 секунды. Это мой первый вопрос, почему один и тот же запрос выполняется существенно по-разному на разных машинах, если они все еще обращаются к одному и тому же серверу и базе данных?

Во-вторых, если я беру текстовый запрос и превращаю его в обычный t-sql и запускаю его, это снова занимает всего 2 секунды. Это подводит меня к моей наиболее вероятной причине, но также и к вопросу, является ли это случаем перехвата параметров, вызывающим снижение производительности?

Я попытался выполнить точно такой же запрос относительно того, что отслеживается трассировкой и добавляется OPTION (RECOMPILE) в конце, а затем он выполняется за 2 секунды. Ранее я также мог устранить проблему, перестроив индексы в основной таблице, которую использовал запрос, поскольку они сильно фрагментировались. Однако сегодня впервые это не сработало.

Комментарии:

1. Для меня это звучит как поиск параметров. Анализатор запросов кэшировал плохой план для вашего конкретного использования. Включено ли у вас «Хранилище запросов». Это помогает выявлять плохие планы и позволяет оценивать и принудительно выполнять конкретные планы для каждого SP. Отправляет ли Dapper запрос, завернутый в sp_executesql. Я не уверен, что ОПЦИЯ RECOMPILE будет работать над этим, вам придется протестировать ее, поскольку это может рассматриваться как отдельный пакетный оператор, чем когда вы помещаете запрос в SP или ssms.

2. @RossBush — что такое хранилище запросов? Я попробовал точно такой же запрос, завернутый в sp_executesql с ОПЦИЕЙ (ПЕРЕКОМПИЛИРОВАТЬ), и это сработало. Однако я подумал, что если бы это был плохой кэшированный план, то у моего коллеги была бы та же проблема при его запуске, что и у меня.

3. Ваш коллега мог работать с другими параметрами или какое-то событие могло вызвать перекомпиляцию до того, как была выполнена их команда. Есть еще одна вещь, которую следует учитывать. Был ли вызов базы данных заключен в область транзакции? Если бы вы или другой разработчик находились на точке останова, находясь в tx, то это также могло бы объяснить такое поведение.

4. @RossBush — мой коллега запустил его точно так, как есть (как в том, что мы получили из трассировки). Мы сделали это с разницей в несколько минут (мой первый). После того, как он сказал, что у него все прошло нормально, я попробовал свой снова и снова столкнулся с той же проблемой. Что касается вызова db, то это стандартный запрос dapper.

5. SQL Server кэширует планы запросов, основанные не только на хэше инструкции SQL, но и на текущем наборе значений @@OPTIONS. Одна из наиболее распространенных причин «Это медленно в приложении, но быстро в SSMS» связана с тем, что SSMS подключается с включенным ARITHABORT, но большинство других подключений с отключенным ARITHABORT. Ознакомьтесь с руководством по архитектуре обработки запросов , чтобы лучше понять, как все это работает.