¿Es mejor ejecutar muchos comandos sql con una conexión, o reconectar cada vez?

Aquí está mi código de prueba, que parece sugerir que es mejor conectarse varias veces en lugar de conectarse solo una vez.

¿Estoy haciendo algo 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); 

Salida:

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

Actualizar:

OK, entonces aquellos que dijeron que sería más rápido con una conexión lo tienen. (aunque la diferencia es marginal, si corresponde). Aquí está el código revisado y la salida:

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

Salida:

 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 

Actualizar:

la diferencia es más sorprendente si utilizo SQLConnection.ClearAllPools() después de cada función:

Salida:

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

De forma predeterminada, SqlConnection usará la agrupación de conexiones. Por lo tanto, es probable que su código realmente no abra muchas conexiones en ningún caso.

Puede controlar si SqlConnection utilizará la agrupación habilitando o deshabilitando el grupo en la conexión, dependiendo de para qué DB sea la cadena de conexión, la syntax variará.

Consulte aquí para obtener más información si utiliza MSSQLServer. Pruebe configurar Pooling = false en la cadena de conexión y vea si hace una diferencia.

Definitivamente, es mejor tener una conexión. Tal vez está ejecutando su punto de referencia con poca cantidad de datos. Intente boost el número a 1,000 o 10,000.

Otro punto es que, dependiendo de la configuración de su aplicación, puede pensar que se está ejecutando con múltiples conexiones, pero .NET está agrupando conexiones para usted, por lo que básicamente se está ejecutando con las mismas conexiones.

Dado que .NET reutiliza las conexiones (“agrupación de conexiones”), no hay demasiados gastos indirectos en la creación de una nueva instancia de DbConnection varias veces seguidas. ADO.NET solo reutilizará la conexión debajo del capó. Es por eso que es bueno que elimine el objeto SqlConnection cada vez, diciéndole a .NET que puede devolverlo al grupo.

Sin embargo, puede boost el rendimiento de varias inserciones utilizando el procesamiento por lotes de ADO.NET . En ese caso, puede tener varios miles de insertos por segundo. Si el rendimiento es crítico, incluso puede considerar el uso de SQLBulkCopy .

Además, su primer par de resultados es bastante extraño: 30 s para 100 inserciones?

En general, la agrupación de conexiones de .NET debería hacer que “no importe”, ya que hace un gran trabajo de reciclaje de conexiones para usted. Pero mi práctica es usar una única conexión para un montón de transacciones que sé que tendrán lugar juntas. Creo que los tiempos son una indicación de que el grupo de conexiones hace su trabajo y simplemente variaciones en las ejecuciones.

SqlClient agrupará sus conexiones. En su primer caso con uno abierto, hará el trabajo de abrir la conexión. Cada otra ejecución usará la conexión agrupada. Si invierte su orden y hace “muchas conexiones” primero, esperaría que vea el resultado opuesto.