Время ожидания запроса в .Net SqlCommand.ExecuteNonQuery, работает в SQL Server Management Studio - PullRequest
7 голосов
/ 12 июня 2009

Обновление: проблема решена и остается решенной. Если вы хотите увидеть сайт в действии, посетите Tweet08

У меня есть несколько запросов, которые работают по-разному в SSMS по сравнению с тем, когда они выполняются внутри моего приложения .Net. SSMS работает нормально в течение секунды. Вызов .Net истекает через 120 секунд (время ожидания соединения по умолчанию).

Я сделал трассировку SQL (и собрал все ). Я видел, что параметры подключения одинаковы (и соответствуют значениям по умолчанию для SQL Server). SHOWPLAN Все, однако, показывают огромную разницу в оценках строк, и, следовательно, рабочая версия делает агрессивную таблицу Spool, где-как неудачный вызов не делает.

В SSMS типы данных временных переменных основаны на сгенерированных параметрах SQL в .Net, поэтому они одинаковы.

Ошибка выполняется под Cassini в сеансе отладки VS2008. Успех под SSMS 2008. Оба работают на одном сервере назначения из одной сети на одной машине.

Запрос в SSMS:

DECLARE @ContentTableID0 TINYINT
DECLARE @EntryTag1 INT
DECLARE @ContentTableID2 TINYINT
DECLARE @FieldCheckId3 INT
DECLARE @FieldCheckValue3 VARCHAR(128)
DECLARE @FieldCheckId5 INT
DECLARE @FieldCheckValue5 VARCHAR(128)
DECLARE @FieldCheckId7 INT 
DECLARE @FieldCheckValue7 VARCHAR(128)
SET @ContentTableID0= 3
SET @EntryTag1= 8
SET @ContentTableID2= 2
SET @FieldCheckId3= 14
SET @FieldCheckValue3= 'igor'
SET @FieldCheckId5= 33
SET @FieldCheckValue5= 'a'
SET @FieldCheckId7= 34
SET @FieldCheckValue7= 'a'

SELECT COUNT_BIG(*)
FROM dbo.ContentEntry AS mainCE
WHERE GetUTCDate() BETWEEN mainCE.CreatedOn AND mainCE.ExpiredOn
AND (mainCE.ContentTableID=@ContentTableID0)
AND ( EXISTS (SELECT *
              FROM dbo.ContentEntryLabel
              WHERE ContentEntryID = mainCE.ID
              AND GetUTCDate() BETWEEN CreatedOn AND ExpiredOn
              AND LabelFacetID = @EntryTag1))
      AND (mainCE.OwnerGUID IN (SELECT TOP 1 Name
                                FROM dbo.ContentEntry AS innerCE1
                                WHERE GetUTCDate() BETWEEN innerCE1.CreatedOn AND innerCE1.ExpiredOn
                                AND (innerCE1.ContentTableID=@ContentTableID2
                                     AND EXISTS (SELECT *
                                                 FROM dbo.ContentEntryField
                                                 WHERE ContentEntryID = innerCE1.ID
                                                 AND (ContentTableFieldID = @FieldCheckId3
                                                      AND DictionaryValueID IN (SELECT dv.ID
                                                                                FROM dbo.DictionaryValue AS dv
                                                                                WHERE dv.Word LIKE '%' + @FieldCheckValue3 + '%'))
                                                )
                                    )
                               )
           OR EXISTS (SELECT *
                      FROM dbo.ContentEntryField
                      WHERE ContentEntryID = mainCE.ID
                      AND (   (ContentTableFieldID = @FieldCheckId5
                               AND DictionaryValueID IN (SELECT dv.ID
                                                         FROM dbo.DictionaryValue AS dv
                                                         WHERE dv.Word LIKE '%' + @FieldCheckValue5 + '%')
                              )
                           OR (ContentTableFieldID = @FieldCheckId7
                               AND DictionaryValueID IN (SELECT dv.ID
                                                         FROM dbo.DictionaryValue AS dv
                                                         WHERE dv.Word LIKE '%' + @FieldCheckValue7 + '%')
                               )
                          )
                     )
          )

Версия трассировки вызова .Net ( добавлено некоторое форматирование ):

exec sp_executesql N'SELECT COUNT_BIG(*) ...'
,N'@ContentTableID0 tinyint
,@EntryTag1 int
,@ContentTableID2 tinyint
,@FieldCheckId3 int
,@FieldCheckValue3 varchar(128)
,@FieldCheckId5 int
,@FieldCheckValue5 varchar(128)
,@FieldCheckId7 int
,@FieldCheckValue7 varchar(128)'
,@ContentTableID0=3
,@EntryTag1=8
,@ContentTableID2=2
,@FieldCheckId3=14
,@FieldCheckValue3='igor'
,@FieldCheckId5=33
,@FieldCheckValue5='a'
,@FieldCheckId7=34
,@FieldCheckValue7='a'

Ответы [ 8 ]

4 голосов
/ 12 июня 2009

Это не ваши индексы.

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

Вы заметите, что версия, которую вы тестируете в SSMS, и версия, которую показывает профилировщик, не идентичны, потому что версия профилировщика показывает, что ваше приложение .Net выполняет его через sp_executesql. Если вы извлечете и выполните полный текст SQL, который на самом деле выполняется для вашего приложения, то я считаю, что вы увидите ту же проблему производительности с тем же планом запроса.

К вашему сведению: отличающиеся планы запросов являются ключевым индикатором перехвата параметров.

ИСПРАВЛЕНИЕ: Самый простой способ исправить это, предполагая, что он выполняется на SQL Server 2005 или 2008, это добавить пункт «OPTION (RECOMPILE)» в качестве последней строки вашего оператора SELECT. Имейте в виду, что вам может потребоваться выполнить его дважды, прежде чем он заработает, и это не всегда работает в SQL Server 2005. Если это произойдет, есть другие шаги, которые вы можете предпринять, но они немного более сложны.

Одна вещь, которую вы можете попробовать, это проверить и посмотреть, включена ли «Принудительная параметризация» для вашей базы данных (это должно быть в свойствах базы данных SSMS, на странице параметров). Чтобы отключить принудительную параметризацию, выполните следующую команду:

    ALTER DATABASE [yourDB] SET  PARAMETERIZATION SIMPLE 
2 голосов
/ 13 июля 2011

Я столкнулся с этой ситуацией сегодня, и исправление, решившее мою проблему, заключается в использовании WITH (NOLOCK) при выполнении выбора для таблиц:

Например: если ваш хранимый процесс имеет T-SQL, который выглядит следующим образом:

SELECT * FROM [dbo].[Employee]

Измените его на

SELECT * FROM [dbo].[Employee] WITH (NOLOCK)

Надеюсь, это поможет.

1 голос
/ 12 июня 2009

Раньше у меня были нерабочие дни, например, мои индексы, и я получил тот же результат, что и вы. sp_recompile может перекомпилировать sproc ... или, если это не сработает, sp_recompile можно запустить на таблице, и все sprocs, которые действуют на эту таблицу, будут перекомпилированы - работает для меня каждый раз.

0 голосов
/ 12 июня 2009

Скорее всего, ваши .Net программы передают переменные как NVARCHAR , а не как VARCHAR . Я полагаю, что ваши индексы находятся в столбцах VARCHAR (судя по вашему сценарию), а условие типа ascii_column = @unicodeVariable фактически не поддерживает SARG. В этом случае план должен генерировать сканирование, где в SSMS будет генерироваться поиск, поскольку переменная имеет правильный тип.

Убедитесь, что вы передаете всю свою строку в качестве параметров VARCHAR, или измените свой запрос для явного приведения переменных, например:

SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + CAST(@FieldCheckValue5 AS VARCHAR(128)) + '%'
0 голосов
/ 12 июня 2009

Я видел такое поведение раньше, и это может быть большой проблемой с o / r mappers, которые используют sp_executesql. Если вы изучите планы выполнения, вы, вероятно, обнаружите, что запрос sp_executesql не использует индексы. Я потратил немало времени, пытаясь найти исправление или объяснение этого поведения, но нигде не получил.

0 голосов
/ 12 июня 2009

Установлено, и этот сервер, сервер разработки, не работал под управлением SQL Server 2005 с пакетом обновления 3 (SP3). Пытался установить это (с необходимой перезагрузкой), но не установил. Как ни странно, и код, и SSMS возвращаются в течение секунды.

Woot, это HEISENBUG.

0 голосов
/ 12 июня 2009

Скорее всего, это связано с индексом. Была похожая проблема с приложением .Net против SSMS (в частности, в процедуре, использующей временную таблицу с <100 строк). Мы добавили кластерный индекс в таблицу, и после этого он вылетел из .Net. </p>

0 голосов
/ 12 июня 2009

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

SET ARITHABORT OFF

Есть ли время ожидания? Если это так, то это ваша индексация и статистика

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