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

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

Я что-то не так делаю?

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

Обновление:

ОК, так что те, кто сказал, что это будет быстрее с одним подключением, имеют его.(хотя разница незначительна, если есть.) Вот пересмотренный код и вывод:

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

Обновление:

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

Вывод:

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

Ответы [ 5 ]

33 голосов
/ 12 мая 2011

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

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

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

10 голосов
/ 12 мая 2011

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

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

7 голосов
/ 12 мая 2011

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

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

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

3 голосов
/ 12 мая 2011

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

3 голосов
/ 12 мая 2011

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

...