Могу ли я остановить вызов sp_reset_connection для повышения производительности?

Моя трассировка профилировщика показывает, что exec sp_reset_connection вызывается между каждым вызовом sql или вызовом процедуры. Есть причины , но могу ли я предотвратить его вызов, если я уверен, что это лишнее, для повышения производительности?

UPDATE: Причина, по которой я предполагаю, что это может улучшить производительность, двояка:

  • SQL Server не нуждается в состоянии подключения reset. Я думаю, что это будет относительно незначительное улучшение.
  • Уменьшенная латентность сети, потому что клиенту не нужно отправлять exec sp_reset_connection, ждать ответа, а затем отправлять любой SQL-код, который он действительно хочет выполнить.

Второе преимущество - это то, что меня интересует, потому что в моей архитектуре клиенты иногда находятся на некотором расстоянии от базы данных. Если для каждой sql-партии или rpc требуется двойное округление, это удваивает влияние любой латентности сети. Устранение таких двойных вызовов может потенциально повысить производительность.

Да, есть много других вещей, которые я мог бы сделать, чтобы улучшить производительность, например, перепроектировать приложение, и я большой поклонник решения основной причины проблем, но в этом случае я просто хочу знать, возможно ли это для предотвращения вызова sp_reset_connection. Затем я могу проверить, есть ли какие-либо улучшения производительности и правильно оценить риски, не вызвав этого.

Это вызывает другой вопрос: действительно ли сетевое общение с sp_reset_connection происходит, как описано выше? Т.е. клиент отправляет exec sp_reset_connection, ждет ответа, а затем отправляет реальный sql? Или все это входит в один кусок?

Ответы

Ответ 1

Если вы используете .NET для подключения к SQL Server, отключение дополнительного вызова reset было отключено как .NET 3.5 - см. здесь. (Свойство остается, но ничего не делает.)

Я предполагаю, что Microsoft поняла (как кто-то экспериментировал здесь), что открытие двери во избежание reset было намного опаснее, чем было получить (вероятно ) небольшой прирост производительности. Не могу сказать, что я их виню.


Клиент отправляет exec sp_reset_connection, ждет ответа, а затем отправляет реальный sql?

EDIT: Я ошибся - см. здесь - ответ - нет.

Сводка: в сообщении TDS есть специальный бит, который указывает, что соединение должно быть reset, а SQL Server автоматически выполняет sp_reset_connection. Он появляется как отдельная партия в Profiler и всегда будет выполняться до фактического запроса, который вы хотели выполнить, поэтому мой тест был недействительным.

Да, он отправляется в отдельной партии.

Я собрал небольшую пробную программу С#, чтобы продемонстрировать это, потому что мне было любопытно:

using System.Data.SqlClient;

(...)

private void Form1_Load(object sender, EventArgs e)
{
    SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
    csb.DataSource = @"MyInstanceName";
    csb.IntegratedSecurity = true;
    csb.InitialCatalog = "master";
    csb.ApplicationName = "blarg";

    for (int i = 0; i < 2; i++)
        _RunQuery(csb);
}

private void _RunQuery(SqlConnectionStringBuilder csb)
{
    using (SqlConnection conn = new SqlConnection(csb.ToString()))
    {
        conn.Open();

        SqlCommand cmd = new SqlCommand("WAITFOR DELAY '00:00:05'", conn);

        cmd.ExecuteNonQuery();
    }
}

Запустите Профилировщик и прикрепите его к выбранному вами экземпляру, отфильтровав имя фиктивного приложения, которое я предоставил. Затем положите точку останова на строку cmd.ExecuteNonQuery(); и запустите программу.

В первый раз, когда вы переходите, просто выполняется запрос, и все, что вы получаете, - это событие SQL: BatchCompleted после 5 секунд ожидания. Когда точка останова попадает во второй раз, все, что вы видите в профилировщике, по-прежнему остается единственным событием. Когда вы переходите снова, вы сразу видите событие exec sp_reset_connection, а затем после задержки появляется событие SQL: BatchCompleted.

удаp >

Единственный способ избавиться от вызова exec sp_reset_connection (который может или не может быть законной проблемой производительности для вас) - это отключить пул соединений .NET. И если вы планируете это сделать, вы, скорее всего, захотите создать свой собственный механизм объединения пулов, потому что просто отключить его и ничего не делать больше, возможно, повредит больше, чем ударить по лишнему кругообороту, и у вас будет для решения проблем корректности вручную.

Ответ 2

Лично я оставил бы его.

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

Чтобы быть справедливым, вы получите большее повышение производительности, не запуская профилировщик против вашей производственной базы данных. И есть ли у вас какие-либо цифры или статьи или рекомендации о том, что вы можете получить от этого, пожалуйста?

Ответ 3

Этот Q/A может быть полезен: Что такое "exec sp_reset_connection" в Sql Server Profiler?

Однако, я быстро проверил использование Entity Framework и MS-SQL 2008 R2. Он показывает, что "exec sp_reset_connection" не занимает много времени после первого вызова:

for (int i = 0; i < n; i++)
{
    using (ObjectContext context = new myEF())
    {

        DateTime timeStartOpenConnection = DateTime.Now;
        context.Connection.Open();
        Console.WriteLine();
        Console.WriteLine("Opening connection time waste: {0} ticks.", (DateTime.Now - timeStartOpenConnection).Ticks);

        ObjectSet<myEntity> query = context.CreateObjectSet<myEntity>();
        DateTime timeStart = DateTime.Now;
        myEntity e = query.OrderByDescending(x => x.EventDate).Skip(i).Take(1).SingleOrDefault<myEntity>();
        Console.Write("{0}. Created By {1} on {2}... ", e.ID, e.CreatedBy, e.EventDate);
        Console.WriteLine("({0} ticks).", (DateTime.Now - timeStart).Ticks);

        DateTime timeStartCloseConnection = DateTime.Now;
        context.Connection.Close();
        context.Connection.Dispose();
        Console.WriteLine("Closing connection time waste: {0} ticks.", (DateTime.Now - timeStartCloseConnection).Ticks);
        Console.WriteLine();
    }
}

И результат был следующим:

Отключить время соединения: 5390101. 585. Создано sa 12/20/2011 2:18:23 PM... (2560183 тика). Задержка закрытия соединения: 0 тиков.

Время открытия соединения: 0 тиков. 584. Создано sa 12/20/2011 2:18:20 PM... (1730173 тиков). Задержка закрытия соединения: 0 тиков.

Время открытия соединения: 0 тиков. 583. Создано sa 12/20/2011 2:18:17 PM... (710071 тиков). Задержка закрытия соединения: 0 тиков.

Время открытия соединения: 0 тиков. 582. Создано sa 12/20/2011 2:18:14 PM... (720072 клещей). Задержка закрытия соединения: 0 тиков.

Время открытия соединения: 0 тиков. 581. Создано sa 12/20/2011 2:18:09 PM... (740074 тика). Задержка закрытия соединения: 0 тиков.

Итак, окончательный вывод: не беспокойтесь о "exec sp_reset_connection"! Он ничего не теряет.

Ответ 4

Просто держите соединение открытым, а не возвращайте его в пул, и выполните все команды в этом соединении.