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

Лучше ли выполнять многие команды sql с одним соединением или повторно подключаться каждый раз?

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

Я что-то делаю неправильно?

int numIts = 100;
Stopwatch sw = new Stopwatch();
sw.Start();
using (SqlConnection connection = new SqlConnection(connectionParameters))
{   
            connection.Open();
    for(int i = 0; i < numIts; i++)
    {
        SqlCommand command = new SqlCommand(sqlCommandName, connection);
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.AddWithValue(par1Name, par1Val);
                command.Parameters.AddWithValue(par2Name, par2Val);
        using(SqlDataReader reader = command.ExecuteReader())
        {
        }
    }
}
sw.Stop();
TimeSpan durationOfOneConnectionManyCommands = sw.Elapsed;
Console.WriteLine(durationOfOneConnectionManyCommands);

sw.Reset();

sw.Start();
for(int i = 0; i < numIts; i++)
{
    using (SqlConnection connection = new SqlConnection(connectionParameters))
    {   
                connection.Open();
        SqlCommand command = new SqlCommand(sqlCommandName, connection);
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.AddWithValue(par1Name, par1Val);
                command.Parameters.AddWithValue(par2Name, par2Val);
        using(SqlDataReader reader = command.ExecuteReader())
        {
        }
    }                               
}
sw.Stop();
TimeSpan durationOfManyConnections = sw.Elapsed;
Console.WriteLine(durationOfManyConnections);

Вывод:

//output:
//00:00:24.3898218   // only one connection established
//00:00:23.4585797   // many connections established.
//
//output after varying parameters (expected much shorter):
//00:00:03.8995448
//00:00:03.4539567

Update:

Хорошо, так что те, кто сказал, что это будет быстрее, с одним соединением. (хотя разница незначительна, если таковая имеется). Здесь пересмотренный код и вывод:

public void TimingTest()
{
    numIts = 1000;
    commandTxt = "select " + colNames + " from " + tableName;

    OneConnection();
    ManyConnections();
    OneConnection();
}
private void ManyConnections()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < numIts; i++)
    {
        using (SqlConnection connection = new SqlConnection(connectionParameters))
        {
            connection.Open();
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = commandTxt;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                }
            }
        }
    }
    sw.Stop();
    TimeSpan durationOfManyConnections = sw.Elapsed;
    Console.WriteLine("many connections: " + durationOfManyConnections);
}
private void OneConnection()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    using (SqlConnection connection = new SqlConnection(connectionParameters))
    {
        connection.Open();
        for (int i = 0; i < numIts; i++)
        {
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = commandTxt;
                using (SqlDataReader reader = command.ExecuteReader())
                {
                }
            }
        }
    }
    sw.Stop();
    TimeSpan durationOfOneConnectionManyCommands = sw.Elapsed;
    Console.WriteLine("one connection: " + durationOfOneConnectionManyCommands);
}

Вывод:

one connection: 00:00:08.0410024
many connections: 00:00:08.7278090
one connection: 00:00:08.6368853

one connection: 00:00:10.7965324
many connections: 00:00:10.8674326
one connection: 00:00:08.6346272

Update:

разница более яркая, если я использую SQLConnection.ClearAllPools() после каждой функции:

Вывод:

one connection: 00:00:09.8544728
many connections: 00:00:11.4967753
one connection: 00:00:09.7775865
4b9b3361

Ответ 1

По умолчанию SqlConnection будет использовать пул соединений. Поэтому ваш код, скорее всего, фактически не откроет много соединений в любом случае.

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

См. здесь для получения дополнительной информации, если вы используете MSSQLServer. Попробуйте установить Pooling = false в строку подключения и посмотреть, не изменилось ли это.

Ответ 2

Определенно, лучше иметь одно соединение. Возможно, вы используете свой бенчмарк с небольшим количеством данных. Попробуйте увеличить число до 1000 или 10000.

Другое дело, что, в зависимости от конфигурации вашего приложения, вы можете подумать, что работаете с несколькими подключениями, но .NET объединяет подключения для вас, поэтому вы в основном работаете с одними и теми же соединениями.

Ответ 3

Так как .NET повторно использует соединения ( "объединение пулов" ), не так много накладных расходов при создании нового экземпляра DbConnection несколько раз подряд. ADO.NET будет просто повторно использовать соединение под капотом. Поэтому хорошо, что вы каждый раз удаляете объект SqlConnection, сообщая .NET, что он может вернуть его в пул.

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

Кроме того, ваша первая пара результатов довольно странная: 30 секунд для 100 вставок?

Ответ 4

В общем, пул соединений .NET должен сделать его "неважно", поскольку он отлично справляется с переработкой соединений для вас. Но моя практика заключается в использовании единого соединения для кучи транзакций, которые, как я знаю, будут проходить вместе. Я думаю, что ваши тайминги являются признаком пула соединений, выполняющего свою работу, и просто различий в прогонах.

Ответ 5

SqlClient объединит ваши соединения. В первом случае с одним открытым он выполнит работу по открытию соединения. Каждый другой запуск будет использовать объединенное соединение. Если вы сначала отмените заказ и сделаете "много соединений", я ожидаю, что вы увидите противоположный результат.