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

У меня есть хранимая процедура, которая выполняется намного быстрее из 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:


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

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

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


person Ole Lynge    schedule 29.04.2009    source источник
comment
Еще одна вещь, которую следует учитывать: если у вас есть потеря производительности с ARITHABORT OFF, вы можете СОЕДИНЯТЬ две таблицы с помощью строки и числового поля. В моем случае добавление простой ISNUMERIC(string_field)=1 проверки перед соединением решило проблему :)   -  person Loris    schedule 10.01.2012
comment
Я бы никогда не подумал об этом - очень-очень полезный вопрос / ответ! :) У нас просто есть необработанный SQL-запрос, выполняемый через Dapper, и виноват тот же SET.   -  person Jedidja    schedule 30.10.2012
comment
Помните об установке ARITHABORT ON на уровне приложения ... добавление SET ARITHABORT ON к вашей процедуре не является решением. Когда вы попробуете, вам покажется, что это сработает. Но это только потому, что вы воссоздали процедуру, которая вызвала новую компиляцию. Полная статья здесь: sommarskog. se / query-plan-mystery.html   -  person Zé Carlos    schedule 29.09.2015


Ответы (4)


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

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

Еще одно влияние - строка подключения; например, если вы включите режим MARS, это может незаметно изменить поведение.

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

person Marc Gravell    schedule 29.04.2009
comment
Спасибо. Я посмотрю, как изучить параметры SET. Думаю, это может быть связано с разницей, потому что в остальном запросы идентичны ... - person Ole Lynge; 29.04.2009
comment
Привет, Марк, у меня была эта проблема в течение многих лет в БД, которую я запускаю, и единственным решением было ВКЛЮЧИТЬ / ВЫКЛЮЧИТЬ ARITHABORT в сохраненной процедуре. К сожалению, это продолжается, и я должен изменить параметр ARITHABORT на противоположный тому, что было. Вы знаете какой-либо способ указать моему .NET-приложению использовать те же параметры SET, что и SSMS? - person Eli Perpinyal; 10.02.2010
comment
Можно ли настроить ARITHABORT с Dapper, Марк? Это то, что устанавливается на уровне подключения, а не на уровне команд? Это команда sql, которую я должен вводить каждый раз, когда устанавливаю соединение? - person crush; 18.06.2015
comment
@crush не вызывает беспокойства - dapper просто оборачивает ADO.NET дружественным лицом. Если вам нужно сделать что-то еще в соединении, вам все равно придется это сделать, хотя теперь вы можете по крайней мере использовать .conn.Execute(...). Я чувствую вашу боль: у нас аналогичные требования, но с уровнем изоляции; Было бы неплохо, если бы мы могли установить значение по умолчанию для строки подключения, которое автоматически восстанавливается при сбросе соединения. - person Marc Gravell; 19.06.2015
comment
Да, я понимаю, что это определенно не проблема Dapper. Ищу какое-то глобальное решение. Пока мы устанавливаем его в сохраненной процедуре, что я не считаю хорошим решением. Я читал, что это можно применить на уровне пользователя. Если я установлю опцию для соединения с Execute, знаете ли вы, сохранятся ли эти опции с пулом соединений .NET? Спасибо за ответ! Люблю Даппер. - person crush; 19.06.2015
comment
Помните об установке ARITHABORT ON на уровне приложения ... добавление SET ARITHABORT ON к вашей процедуре не является решением. Когда вы попробуете, вам покажется, что это сработает. Но это только потому, что вы воссоздали процедуру, которая вызвала новую компиляцию. Полная статья здесь: sommarskog. se / query-plan-mystery.html - person Zé Carlos; 29.09.2015

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

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

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

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

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

exec sp_msforeachtable "dbcc dbreindex('?')"

SO сообщения:

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

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

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

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

person Mitch Wheat    schedule 29.04.2009
comment
Я выполнял одни и те же запросы (EXEC sp_Stat @DepartmentID = NULL) сразу после друг друга. Сначала тот, который с SSMS занял 2 секунды. Затем (через несколько секунд) тот, у которого истекло время ожидания .NET. Как вы думаете, это все еще может быть связано с неправильно кешированным планом запроса? - person Ole Lynge; 29.04.2009
comment
либо это, либо статистика устарела, либо индексы необходимо перестроить (что обновляет статистику в соответствующих столбцах) - person Mitch Wheat; 29.04.2009
comment
Я использую точно такие же параметры. И опция WITH RECOMPILE не меняет исход ... - person Ole Lynge; 29.04.2009
comment
В статьях, на которые вы ссылаетесь, похоже, говорится о параметризованных запросах, время выполнения которых зависит от значения параметров. У меня точно такие же значения в этих тестах ... - person Ole Lynge; 29.04.2009
comment
Спасибо. Решение было связано с анализом параметров. Это помогло сохранить значения входных параметров sproc в локальных переменных ... - person Ole Lynge; 13.05.2009

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

person raeldor    schedule 28.07.2016
comment
Аминь, я просто потратил больше дня на это. Запрос был прекрасным и очень простым, я изучил параметры SET и т. Д. Наконец, поигрался со строкой подключения и обнаружил, что это маленькое свойство вызывает резкое снижение производительности при повторении набора результатов (на порядок медленнее). - person Nicholas Smith; 08.05.2018
comment
Для меня это проявилось в основном во время массового копирования SQL. Мне было бы любопытно, если бы такая же ситуация была для других. - person raeldor; 17.05.2018
comment
В моем случае проблема была замечена при повторении относительно больших наборов результатов (2k + записей). Я бы предположил, что это повлияет на результирующий набор любого размера, но влияние на производительность вообще не было бы замечено, если бы вы извлекали только несколько записей (например, 10 мс превращаются в 100 мс, трудно заметить). - person Nicholas Smith; 18.05.2018

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

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

person Andomar    schedule 29.04.2009
comment
Надеюсь, вы сначала изучили свою статистику и индексы! ;) - person Mitch Wheat; 29.04.2009
comment
Да, у нас есть еженедельный план обслуживания статистики и индексов (выполняется каждое воскресенье). Мы воссоздали хранимую процедуру, чтобы удалить все кэшированные планы запросов. - person Andomar; 29.04.2009