Могу ли я остановить вызов sp_reset_connection для повышения производительности? - PullRequest
13 голосов
/ 23 октября 2010

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

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

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

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

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

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

Ответы [ 4 ]

8 голосов
/ 27 апреля 2012

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

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


Отправляет ли клиент exec sp_reset_connection, ждет ответа, а затем отправляет настоящий sql?

РЕДАКТИРОВАТЬ: Я был не прав - см. здесь - ответ - нет.

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

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

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

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();
    }
}

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

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

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

2 голосов
/ 30 октября 2010

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

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

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

2 голосов
/ 08 марта 2012

Этот вопрос может быть полезен: Что означает "exec sp_reset_connection" в Sql Server Profiler?

Однако я провел быстрый тест с использованием Entity Framework и MS-SQL 2008R2.Это показывает, что «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 20.12.2011 14:18:23 ... (2560183 тика).Трата времени закрытия соединения: 0 тиков.

Трата времени открытия соединения: 0 тиков.584. Создано sa 20.12.2011 14:18:20 ... (1730173 тика).Трата времени закрытия соединения: 0 тиков.

Трата времени открытия соединения: 0 тиков.583. Создано sa 20.12.2011 14:18:17 ... (710071 тик).Трата времени закрытия соединения: 0 тиков.

Трата времени открытия соединения: 0 тиков.582. Создано sa 20.12.2011 14:18:14 ... (720072 тика).Трата времени закрытия соединения: 0 тиков.

Трата времени открытия соединения: 0 тиков.581. Создано sa 20.12.2011 14:18:09 ... (740074 тика).Трата времени на закрытие соединения: 0 тиков.

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

0 голосов
/ 23 октября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...