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

Запрос очень медленный в коде, но быстрый в SSMS

У меня довольно простой запрос, в котором я получаю таймауты (для завершения требуется три минуты, я остановил его раньше, чтобы опубликовать этот вопрос), когда он работает в коде, однако, когда я запускаю тот же запрос из на том же компьютере в Sql Server Management Studio запрос будет принимать только 2532 ms первый запрос, когда данные не кэшируются на сервере и 524 ms для повторных запросов.

Вот мой код С#

using (var conn = new SqlConnection("Data Source=backend.example.com;Connect Timeout=5;Initial Catalog=Logs;Persist Security Info=True;User ID=backendAPI;Password=Redacted"))
                using (var ada = new SqlDataAdapter(String.Format(@"
SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt 
FROM [ES_HISTORY] 
inner join [es_history_dt] on [PK_JOB] = [es_historyid] 
Where client_id = @clientID and dt > @dt and (job_type > 4 {0}) {1}
Order by dt desc"
     , where.ToString(), (cbShowOnlyFailed.Checked ? "and Status = 1" : "")), conn))
{
    ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);
    ada.SelectCommand.Parameters.AddWithValue("@dt", dtpFilter.Value);
    //ada.SelectCommand.CommandTimeout = 60;
    conn.Open();
    Logs.Clear();
    ada.Fill(Logs); //Time out exception for 30 sec limit.
}

вот мой код, который я запускаю в SSMS, я вытащил его прямо из ada.SelectCommand.CommandText

declare @clientID varchar(200)
set @clientID = '138'
declare @dt datetime
set @dt = '9/19/2011 12:00:00 AM'

SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt 
FROM [ES_HISTORY] 
inner join [es_history_dt] on [PK_JOB] = [es_historyid] 
Where client_id = @clientID and dt > @dt and (job_type > 4 or job_type = 0 or job_type = 1 or job_type = 4 ) 
Order by dt desc

Что вызывает основное несоответствие разницы во времени?


Чтобы сохранить раздел комментария чистым, я отвечу на некоторые FAQ здесь.

Тот же компьютер и вход в систему используются как для приложения, так и для ssms.

В моем примере запроса возвращается только 15 строк. Однако es_history содержит 11351699 rows и es_history_dt содержит 8588493 rows. Обе таблицы хорошо проиндексированы, а план выполнения в SSMS говорит, что они используют индексные поиски для поиска, чтобы они быстро находились. Программа ведет себя так, как будто она не использует индексы для версии запроса С#.

4b9b3361

Ответ 1

Ваш код в SSMS - это не тот код, который вы запускаете в своем приложении. Эта строка в вашем приложении добавляет параметр NVARCHAR:

 ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);

в то время как в SSMS script вы объявляете его как VARCHAR:

declare @clientID varchar(200)

Из-за правил Приоритет типа данных выражение Where client_id = @clientID в вашем запросе не является SARG-способным, где @clientID имеет тип NVARCHAR (я делаю скачок веры и предполагаю, что столбец client_id имеет тип VARCHAR). Таким образом, приложение запускает сканирование таблицы, где запрос SSMS может быстро искать ключ. Это хорошо известная и понятная проблема с использованием параметра Parameters.AddWithValue и обсуждалась во многих статьях раньше, например. см. Как код доступа к данным влияет на производительность базы данных. Как только проблема понятна, решения тривиальны:

Первое решение является превосходным, поскольку оно решает проблему загрязнения кэша в дополнение к проблеме способности SARG.

Я бы также рекомендовал вам прочитать Медленное приложение, быстро в SSMS? Понимание таинств производительности

Ответ 2

Запустите профайлер на вашем соединении С# - может быть и другая деятельность, о которой вы не знаете.

Ответ 3

Захват плана выполнения из SSMS при ручном запуске вашего запроса, а затем из Profiler при запуске приложения. Сравните и сравните.

Ответ 4

Запустите DBCC FREEPROCCACHE, как было предложено здесь, чтобы убедиться, что проблема не из-за плана выполнения устаревших запросов.