SQL-запрос медленно из кода .NET, но не в интерактивном режиме - PullRequest
8 голосов
/ 02 октября 2009

Мы используем ORM, который выполняет вызов из .NET в хранимую процедуру sp_executesql SQL Server.

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

Глядя на Profiler, я вижу, что выполнение запроса действительно занимает много времени.

Запрос по существу:

exec sp_executesql N'SELECT DISTINCT
FROM [OurDatabase].[dbo].[Contract] [LPLA_1] ) [LPA_L1]
LEFT JOIN [OurDatabase].[dbo].[Customer] [LPA_L2]  ON [LPA_L2].[Customer_ID]=[LPA_L1].[CustomerId] AND [LPA_L2].[Data]=[LPA_L1].[Data])
WHERE ( ( ( ( ( [LPA_L1].[DealerId] = @DealerId1)) 
AND ( [LPA_L2].[Last_Name] = @LastName2))))',N'@DealerId1 varchar(18),@LastName2 varchar(25)',@DealerId1='1234',@LastName2='SMITH'

Меня сбивает с толку: если я скопирую и вставлю запрос, который истекает по времени, в SQL Management Studio и выполню его в интерактивном режиме, он выполнится просто отлично.

Кто-нибудь знает, почему тот же запрос может занять значительно больше времени при выполнении с помощью кода .NET? (Я могу воспроизвести это - запрос, выполненный из кода последовательно, истекает, а запрос, выполненный в интерактивном режиме, последовательно работает нормально.)

Любая помощь приветствуется. Спасибо!

Ответы [ 6 ]

4 голосов
/ 02 октября 2009

Одна вещь, которую я видел несколько раз, - это несоответствие между типами nvarchar и varchar для параметра запроса в индексированном поле. Это может произойти, если вы используете varchar в своей базе данных и явно не устанавливаете тип вашего параметра в .Net, который по умолчанию будет использовать nvarchar.

В этом случае Sql Server выбирает более правильный вариант, а не более эффективный. Вместо того, чтобы просто преобразовать ваш параметр в varchar, который будет сужающим преобразованием, которое может потенциально потерять информацию, база данных будет вынуждена преобразовать каждое значение для этого столбца в таблице в nvarchar (который гарантированно будет успешным без потери информации) , Это не только медленно, но Sql Server больше не сможет использовать индекс. Излишне говорить, что выполнение запроса займет гораздо больше времени.

1 голос
/ 03 октября 2012

Вот что я нашел. У меня ОЧЕНЬ сложный хранимый процесс, который всегда подсчитывает информацию и помещает данные в матрицу из 17 строк, состоящую из 8 столбцов, так как она вызывается / запускается Crystal Reports каждый месяц. База данных prod была на сумасшедшем быстром сервере 96 ГБ! Недавно он был уменьшен до 32 ГБ виртуальной машины. Несмотря на то, что оно было уменьшено - оно во многих отношениях замедляло работу приложения, пока не было добавлено несколько индексов.

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

Вызов proc был довольно прост - 3 параметра. Дата начала, дата окончания и район, по которому необходимо выполнить фильтрацию, - равны нулю ВСЕ. Две даты были переданы из Crystal Reports как символ, и эти сохраненные параметры PROC затем использовались повсюду в этом сумасшедшем сохраненном процессе.

Каждая из 17 строк - в основном использует операторы WITH и сумасшедшие объединения для поиска строк данных перед подсчетом / поворотом результатов ... что НЕ важно в этой статье.

Так что здесь это упрощено ....

CREATE PROCEDURE [dbo].[prcMonthlyStats]
@bDate          datetime
,@eDate         datetime
,@districtStr   varchar(120)
AS
BEGIN
SET NOCOUNT ON;

...

--the @bDate and @eDate params were DIRECTLY used throughout the 2000 lines of SQL,
--to filter data inside and out of WITH statements and various other selects!
--
--TIMES OUT!

...

CREATE PROCEDURE [dbo].[prcMonthlyStats]
@bDateStr       datetime
,@eDateStr      datetime
,@districtStr   varchar(120)
AS
BEGIN
SET NOCOUNT ON;

--FIX!  Declare 2 date time variables and simply assign the 2 date time parameters to them.
DECLARE @bDate      datetime
DECLARE @eDate      datetime
DECLARE @district   varchar(120)

--SET THE VARIABLES FROM THE PARAMETERS PASSED IN!  
SET @bDate = @bDateStr
SET @eDate = @eDateStr
SET @district = @districtStr
.....

--PRESTO! The optimizer could once again use indexes as it should.

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

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

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

Отличие состоит в том, что обновление таблицы для «Company (таблица)» в sp_executesql подается через цепочку вложенных циклов, а текстовый запрос - через цепочку хеш-совпадений. Конструкция представлений выглядит одинаково между двумя версиями (что я и ожидал). К сожалению, остальные очень сложны, и они, кажется, делают в корне разные вещи; даже получение «фактического» плана выполнения не дает фактического времени выполнения для различных подкомпонентов запроса. На самом деле я не вижу причин для того, чтобы sp_executesql выбирал что-то по-другому, но он надежно создает значительно более медленный план.

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

Привет.

1 голос
/ 01 декабря 2010

Просто была такая же проблема.

Восстановление индексов решило проблему.

Возможно, проблема заключается в типе параметров nvarchar против индекса, который находится в столбце varchar ...?

1 голос
/ 13 декабря 2009

У меня такая же проблема, процедура, выполняемая из .net, которая занимает слишком много времени (и не возвращает много строк). Я посылаю строку в sql: «execute selected_procedure @ parameter1 = value1», копирую ее и запускаю в студии управления sql, но там все работает нормально. Неудобство этого случая состоит в том, что в моем запросе я просто добавляю или удаляю ПИСЬМО из значения параметра, чтобы вызвать его. Я очень смущен.

Для информации, я использую полнотекстовые индексы и временные таблицы порционирования, но, как я уже сказал, ЖЕ ЗАПРОС (и я уверен) отлично работает в SQL Management Studio.

0 голосов
/ 02 октября 2009

Дилер ID или фамилия nvarchar (по-другому, чем параметры varchar)?

Это может вызвать преобразование целых индексов. Если вы считаете, что это так, оставьте комментарий, и я объясню более подробно.

...