Почему некоторые SQL-запросы намного медленнее при использовании с SqlCommand? - PullRequest
18 голосов
/ 29 апреля 2009

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

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


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

EXEC sp_Stat
    @DepartmentID = NULL

В .NET / C # следующие промежутки времени после 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 и SqlParameter, но это тот же результат.

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

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


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

SQL Server Profiler показал, что Sql Server Management Studio выполняет следующие SET, что не делает .NET Sql Client Data Provider:


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

Что я узнал? Может быть, использовать профилировщик вместо того, чтобы угадывать ...

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

Ответы [ 4 ]

10 голосов
/ 29 апреля 2009

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

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

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

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

5 голосов
/ 29 апреля 2009

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

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

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

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

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

exec sp_msforeachtable "dbcc dbreindex('?')"

SO сообщений:

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

Отслеживание параметров (или спуфинг) в SQL Server

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

Другой план выполнения для той же хранимой процедуры

1 голос
/ 28 июля 2016

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

0 голосов
/ 29 апреля 2009

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

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

...