Подтвердить что ты не робот

Почему какой-то запрос sql намного медленнее при использовании с SqlCommand?

У меня есть хранимая процедура, которая выполняется намного быстрее из Sql Server Management Studio (2 секунды), чем при запуске с System.Data.SqlClient.SqlCommand (время истекает через 2 минуты).

Что может быть причиной этого?


Подробнее: В Sql Server Management Studio выполняется через 2 секунды (в производственной базе данных):

EXEC sp_Stat
    @DepartmentID = NULL

В .NET/С# следующие тайм-ауты через 2 минуты (в производственной базе данных):

string selectCommand = @"
EXEC sp_Stat
    @DepartmentID = NULL";
string connectionString = "server=***;database=***;user id=***;pwd=***";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    using (SqlCommand command = new SqlCommand(selectCommand, connection))
    {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
            }
        }
    }
}

Я также пробовал с selectCommand = "sp_Stat", CommandType = StoredProcedure и a SqlParameter, но это тот же результат.

И без EXEC это тот же результат.

В почти базе данных, свободной от данных, оба случая заканчиваются менее чем за 1 секунду. Таким образом, это связано с тем, что в базе данных много данных, но, похоже, это происходит только из .NET...


То, что написал Марк Гравелл о разных значениях SET, делает разницу в представленном случае.

Профилировщик SQL Server показал, что Sql Server Management Studio запускает следующее SET, которое поставщик данных .NET Sql не выполняет:


SET ROWCOUNT 0 
SET TEXTSIZE 2147483647 
SET NOCOUNT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ARITHABORT ON 
SET LOCK_TIMEOUT -1 
SET QUERY_GOVERNOR_COST_LIMIT 0 
SET DEADLOCK_PRIORITY NORMAL 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
SET ANSI_NULLS ON 
SET ANSI_NULL_DFLT_ON ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
SET CURSOR_CLOSE_ON_COMMIT OFF 
SET IMPLICIT_TRANSACTIONS OFF 
SET QUOTED_IDENTIFIER ON
SET NOEXEC, PARSEONLY, FMTONLY OFF

Когда я включил их, один и тот же запрос занял одинаковое количество времени в SSMS и .NET. И ответственный SET - это...

SET ARITHABORT ON

Что я узнал? Возможно, использовать профайлер вместо угадывания...

(Решение сначала казалось связанным с параметризацией, но я кое-что перепутал...)

4b9b3361

Ответ 1

Еще одна важная вещь - параметры SET, которые включены. Некоторые из этих параметров значительно изменяют план запроса, чтобы изменить профиль. Некоторые могут иметь огромное влияние, если вы посмотрите (например) на вычисляемый + упорный (и, возможно, проиндексированный) столбец: если параметры SET несовместимы, его можно заставить пересчитать значения, а не используя индексированное значение - которое может изменить поиск индекса в сканирование таблицы + вычисление.

Попробуйте использовать профилировщик, чтобы узнать, какие опции SET "находятся в игре", и посмотрите, меняются ли эти параметры.

Другим воздействием является строка соединения; например, если вы включите MARS, который может изменить поведение тонким образом.

Наконец, транзакции (неявные (TransactionScope) или явные) могут иметь огромное влияние в зависимости от уровня изоляции.

Ответ 2

Это почти наверняка связано с "неправильным" кэшированным планом запросов. Это произошло на SO довольно много раз.

У вас есть актуальная статистика? Регулярный план обслуживания плановых индексов?

Вы можете проверить, определенно ли это из-за плана кешированных запросов, добавив это в определение хранимой процедуры:

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

Это приведет к повторной индексации всей базы данных (осторожно, если база данных очень велика!):

exec sp_msforeachtable "dbcc dbreindex('?')"

Сообщения SO:

Большая разница во времени выполнения хранимого процесса между Managment Studio и TableAdapter.

Параметр Sniffing (или Spoofing) в SQL Server

оптимизировать для неизвестного для SQL Server 2005?

Различные планы выполнения для той же хранимой процедуры

Ответ 3

У нас была аналогичная проблема, когда запрос завершился через 2 секунды в SSMS и потребовался более 90 секунд при вызове из .NET-клиента (мы написали несколько приложений/сайтов VB/С# для его проверки).

Мы подозревали, что план запроса будет другим, и переписал запрос с явным циклом (подсказки "внутреннее соединение цикла" и "с индексом" ). Это решило проблему.

Ответ 4

Имел аналогичную проблему, и оказалось, что MultipleActiveResultSets = true в строке соединения (которая должна иметь минимальное влияние) заключалась в том, что вытягивание записей на 1.5 мили по удаленному соединению занимает 25 минут, а не около 2 минут.