42 votes

Est-il préférable d'exécuter plusieurs commandes SQL avec une seule connexion ou de se reconnecter à chaque fois?

Voici mon code de test, ce qui semble suggérer que c'est mieux de se connecter plusieurs fois au lieu de se connecter une seule fois.

Suis-je en train de faire quelque chose de mal?

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

Sortie:

//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

Mise à jour:

OK, donc ceux qui disent qu'il serait plus rapide w/ une connexion à l'avoir. (bien que la différence est minime, le cas échéant.) Voici le code révisé et de sortie:

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

Sortie:

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

Mise à jour:

la différence est plus frappant si j'utilise SQLConnection.ClearAllPools() après chaque fonction:

Sortie:

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

33voto

Ben Schwehn Points 3162

Par défaut, SqlConnection va utiliser le regroupement de connexion. Par conséquent, votre code n'est plus susceptibles de ne pas ouvrir plusieurs connexions dans les deux cas.

Vous pouvez contrôler si SqlConnection va utiliser le regroupement par l'activation ou la désactivation de la piscine dans la propriété connectionstring, en fonction de ce DB votre chaîne de connexion est pour, la syntaxe varie.

Voir ici pour avoir des infos si vous utilisez MSSQLServer. Essayez de régler une mise en commun=false dans la chaîne de connexion et de voir si cela fait une différence.

10voto

Adrian Carneiro Points 26652

En définitive, il est préférable d’avoir une seule connexion. Vous exécutez peut-être votre point de référence avec une petite quantité de données. Essayez d'augmenter le nombre à 1 000 ou 10 000.

En outre, en fonction de la configuration de votre application, vous pouvez penser que vous utilisez plusieurs connexions, mais que .NET met en pool des connexions pour vous. Vous utilisez donc essentiellement les mêmes connexions.

7voto

Groo Points 19453

Depuis .NET réutilise les connexions ("pooling de connexion"), il n'y a pas beaucoup de frais généraux dans la création d'une nouvelle instance de l' DbConnection plusieurs fois dans une rangée. ADO.NET va réutiliser la connexion sous le capot. C'est pourquoi il est bon vous débarrasser de la SqlConnection objet à chaque fois, de raconter .NET qu'il peut retourner à la piscine.

Toutefois, vous pouvez augmenter les performances de plusieurs insertions en utilisant ADO.NET le traitement par lots. Dans ce cas, vous pouvez avoir facilement plusieurs milliers de plaquettes par seconde. Si la performance est critique, vous pouvez même envisager d'utiliser SQLBulkCopy.

Aussi, votre première paire de résultats est assez étrange: 30 pour 100 des inserts?

3voto

n8wrl Points 12485

En général, le regroupement de connexions de .NET devrait en faire une solution de rechange, car il permet de recycler les connexions pour vous. Mais ma pratique est d’utiliser une seule connexion pour un ensemble de transactions qui, je le sais, se dérouleront ensemble. Je pense que votre minutage est une indication du pool de connexion qui fait son travail et de simples variations dans les exécutions.

3voto

James Kovacs Points 8757

SqlClient mettra en commun vos connexions. Dans votre premier cas avec un ouvert, il s’agira d’ouvrir la connexion. Toute autre exécution utilisera la connexion en pool. Si vous inversez votre ordre et faites "beaucoup de connexions" en premier, je m'attendrais à ce que vous voyiez le résultat inverse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X