Crear conexiones de base de datos: ¿hacerlo una vez o para cada consulta?

101

En este momento creo una conexión de base de datos cuando mi página web se carga por primera vez. Luego proceso la página y ejecuto cualquier consulta contra esa conexión. ¿Es esta la mejor manera de hacerlo o debería crear una conexión de base de datos cada vez que ejecuto una consulta?

ps Tiene más sentido para mí crear 1 conexión y usarla, pero no sé si esto puede causar otros problemas.

Estoy usando C # (ASP.NET) con MSSQL.

webnoob
fuente

Respuestas:

124

Si crea uno por consulta / transacción, es mucho más fácil administrar "cerrar" las conexiones.

Puedo ver por qué el sentido común dicta que debe abrir uno y usarlo en todo momento, pero se encontrará con problemas con conexiones caídas y subprocesos múltiples. Por lo tanto, su próximo paso será abrir un grupo, digamos de 50, conexiones y mantenerlas abiertas, distribuyéndolas a diferentes procesos. Y luego descubrirá que esto es exactamente lo que el marco .NET ya hace por usted .

Si abre una conexión cuando la necesita y la desecha cuando haya terminado, eso no cerrará la conexión, simplemente la devolverá al grupo de conexiones para que se vuelva a usar.

pdr
fuente
Estaba leyendo ese artículo cuando lo publicaste :) Gracias.
webnoob
2
La página web a la que se vinculó es específica de SQL Server. ¿Proporciona .NET también una agrupación automática cuando se conecta a otras bases de datos, por ejemplo, Oracle, Sqlite, MySql?
briddums
@briddums: creo que eso depende del conector. .Net, por ejemplo, no proporciona un conector MySql. Está escrito y mantenido por MySql. Y aunque funciona, en mi experiencia, la implementación anterior estaba lejos de ser libre de errores.
ZweiBlumen
1
@briddums: depende del ensamblaje del proveedor. Estoy seguro de que tanto la implementación de Oracle de Microsoft como la propia de Oracle admiten la agrupación de conexiones, porque las he usado. Escuché que hay un MySql que lo hace, y espero que los proveedores en Spring.NET admitan la agrupación, pero es mejor buscar o preguntar al proveedor directamente que preguntarme a mí.
pdr
1
Debe saber que abrir, ejecutar una consulta y eliminar una conexión, incluso en un bucle, es igual de rápido y, a veces, MÁS RÁPIDO que abrirlo una vez y hacer un bucle en la consulta. Siempre solo disponer. Es más seguro y RÁPIDO. No se preocupe por la sobrecarga de obtener una conexión del grupo, es muy trivial.
smdrager
38

Se recomienda crear una conexión por consulta, y en el caso de mostrar datos, la mejor práctica es hacer que la consulta traiga todos los datos necesarios de una vez.

Información de antecedentes:

En .NET, las llamadas SqlConnection.Open()utilizarán de manera transparente de forma transparente la agrupación de conexiones (consulte "Uso de la agrupación de conexiones con SQL Server" en MSDN). Por lo tanto, puede tomar una nueva conexión usando Open()y llamar Close()cuando haya terminado, y .NET hará lo correcto.

Tenga en cuenta que sin una agrupación de conexiones, una conexión por consulta sería una muy mala idea porque crear conexiones de bases de datos reales puede ser muy costoso (autenticación, sobrecarga de red, etc.), y el número de conexiones abiertas simultáneas suele ser muy limitado.

Oded
fuente
77
@webnoob: dado que .NET usa la agrupación de conexiones, no, no lo hace. La razón es que las conexiones pueden cerrarse, reasignarse, etc., por lo que reutilizar una conexión no es una buena práctica.
Oded
11
-1 La respuesta es bastante engañosa. Crear una conexión por consulta es una muy mala idea. Lo que probablemente quiere decir es "recuperar una nueva conexión para cada consulta del grupo de conexiones", pero eso no es lo mismo que crear una conexión.
sleske
1
@sleske: ¿en qué se diferencia eso de la respuesta de pdr?
Oded
3
@Oded: Ah, ya veo. En .NET, las llamadas SqlConnection.Open()siempre utilizarán de manera transparente la agrupación de conexiones. Por lo tanto, la diferencia entre "abrir una conexión" y "recuperar una conexión desde un grupo" no existe. Mi malentendido. Me tomé la libertad de editar una pequeña explicación de la pregunta y retomé la votación.
sleske
2
@ eaglei22: ciertamente debería hacerlo (ver docs.microsoft.com/en-us/dotnet/framework/data/adonet/… ). En general, usted quiere devolver la conexión a la piscina tan pronto como sea posible, sin embargo, si va a emitir una serie de consultas en secuencia, que podría ser mejor reutilizar una conexión como usted sugiere. Tendría que probar y ver qué enfoque es mejor para usted (no sé qué criterios utiliza, verifique ambas formas y vea el efecto en las métricas elegidas).
Oded
0

Recuerde que todo esto está en el contexto del ecosistema .Net.

Los desarrolladores a veces quieren "optimizar" su código para reutilizar sus objetos de conexión. Dado el contexto de esta pregunta, esto casi siempre es un error.

ADO.Net tiene una característica llamada Connection Pooling . Cuando crea y abre un nuevo objeto de conexión, lo que realmente está haciendo es solicitar una conexión de un grupo. Cuando cierra una conexión, la devuelve al grupo.

Es importante comprender los objetos que usamos directamente en el código: SqlConnection, MySqlConnection, OleDbConnectio, etc., son solo envoltorios alrededor de una conexión subyacente real administrada por ADO.Net, y las conexiones reales de ADO.Net son mucho más "pesadas" y más caras. desde el punto de vista del rendimiento. Son estos objetos subyacentes los que tienen preocupaciones como la autenticación, el tránsito de la red, el cifrado y esas cosas superan con creces la pequeña cantidad de memoria en el objeto que realmente ve en su propio código.

Cuando intentas reutilizar tu objeto de conexión, rompes la capacidad de ADO.Net de administrar eficazmente las conexiones subyacentes importantes. Ganas eficiencia en lo pequeño a expensas de lo mucho más grande.

Reutilizar una conexión a través de una aplicación o solicitud http también puede obligarlo a serializar accidentalmente algo que de otro modo podría ejecutarse en paralelo y convertirse en un cuello de botella de rendimiento. He visto que esto sucede en aplicaciones reales.

En el caso del ejemplo de la página web aquí, donde al menos solo mantiene la conexión pequeña durante la duración de una sola solicitud / respuesta http, podría ganar aún más eficiencia al evaluar qué consultas ejecuta en su canal de solicitudes, e intente obtener reducirlos a la menor cantidad posible de solicitudes a la base de datos (sugerencia: puede enviar más de una consulta en una sola cadena SQL y usar DataReader.NextResult()o verificar diferentes tablas en una DataSetpara moverse entre ellas).

En otras palabras, en lugar de pensar en términos de reutilizar una conexión para una aplicación o solicitud http versus una conexión por consulta, piense en términos de una conexión por cada vez que llame a la base de datos ... cada viaje de ida y vuelta. Luego trate de minimizar la cantidad de conexiones minimizando la cantidad de esos viajes. De esta manera puedes satisfacer ambos objetivos.


Pero ese es solo un tipo de optimización. También se optimiza el tiempo del programador y se obtiene una reutilización efectiva del código. Los desarrolladores no quieren escribir el mismo código repetitivo una y otra vez solo para obtener un objeto de conexión que esté abierto y listo para usar. No solo es tedioso, es una forma de introducir errores en un programa.

Incluso aquí, sin embargo, generalmente es mejor tener una conexión por consulta (o ida y vuelta). Hay otros patrones que puede usar para evitar reescribir el mismo código repetitivo. Aquí hay un ejemplo que me gusta, pero hay muchos otros.

Joel Coehoorn
fuente
Llego tarde a esta fiesta, pero creo que esta respuesta cubre algunos puntos importantes :)
Joel Coehoorn