Création de connexions à la base de données - Faites-le une fois ou pour chaque requête?

101

Pour le moment, je crée une connexion à la base de données lorsque ma page Web est chargée pour la première fois. Je traite ensuite la page et lance toutes les requêtes sur cette connexion. Est-ce la meilleure façon de le faire ou devrais-je créer une connexion à une base de données chaque fois que j'exécute une requête?

ps Il est plus logique pour moi de créer une connexion et de l'utiliser, mais je ne sais pas si cela peut causer d'autres problèmes.

J'utilise C # (ASP.NET) avec MSSQL.

webnoob
la source

Réponses:

124

Si vous en créez une par requête / transaction, il est beaucoup plus facile de gérer la "fermeture" des connexions.

Je peux comprendre pourquoi le bon sens vous dit d’en ouvrir un et de l’utiliser tout au long du processus, mais vous rencontrerez des problèmes de perte de connexion et de multithreading. Votre prochaine étape sera donc d'ouvrir un pool, par exemple 50, et de les garder tous ouverts, en les distribuant à différents processus. Et ensuite, vous découvrirez que c'est exactement ce que le framework .NET fait déjà pour vous .

Si vous ouvrez une connexion lorsque vous en avez besoin et que vous vous en débarrassez une fois que vous avez terminé, la connexion ne sera pas fermée, elle sera simplement renvoyée dans le pool de connexions pour être utilisée à nouveau.

pdr
la source
Je venais de lire cet article quand vous l'avez posté :) Merci.
Webnoob
2
La page Web à laquelle vous avez accédé est spécifique à SQL Server. Est-ce que .NET fournit également le pooling automatique lors de la connexion à d'autres bases de données, par exemple Oracle, Sqlite, MySql?
briddums
@briddums - Je pense que cela dépend du connecteur. .Net, par exemple, ne fournit pas de connecteur MySql. C'est écrit et maintenu par MySql. Et bien que cela fonctionne, selon mon expérience, la mise en œuvre précédente était loin d'être exempte de bogues.
ZweiBlumen
1
@briddums: dépend de l'assembly du fournisseur. Je suis certain que l'implémentation Oracle de Microsoft et celle d'Oracle prennent en charge le regroupement de connexions, car je les ai utilisées. J'ai entendu dire que MySql en est un, et je m'attendrais à ce que les fournisseurs de Spring.NET prennent en charge le pooling, mais vous feriez mieux de rechercher ou de demander directement au fournisseur que de me le demander.
pdr
1
Il faut savoir que l'ouverture, l'exécution d'une requête et la suppression d'une connexion, même en boucle, sont tout aussi rapides et parfois plus rapides que de l'ouvrir une fois et de boucler la requête. Toujours juste disposer. C'est plus sécurisé et rapide. Ne vous inquiétez pas des frais généraux liés à l’obtention d’une connexion de la piscine - c’est tellement trivial.
smdrager
38

La meilleure pratique consiste à créer une connexion par requête - et dans le cas de l'affichage de données, la meilleure pratique consiste à faire en sorte que la requête fournisse toutes les données nécessaires en une seule fois.

Informations d'arrière-plan:

Dans .NET, l'appel SqlConnection.Open()utilise par défaut toujours de manière transparente le regroupement de connexions (voir "Utilisation du regroupement de connexions avec SQL Server" sur MSDN). Ainsi, vous pouvez simplement saisir une nouvelle connexion en utilisant Open(), et appeler Close()lorsque vous avez terminé, et .NET fera le bon choix.

Notez que sans regroupement de connexions, une connexion par requête serait une très mauvaise idée car la création de connexions à une base de données réelle peut être très coûteuse (authentification, surcharge du réseau, etc.) et que le nombre de connexions ouvertes simultanées est généralement très limité.

Oded
la source
7
@webnoob - Puisque .NET utilise le pooling de connexion, non. La raison en est que les connexions peuvent être fermées, réaffectées, etc., de sorte que la réutilisation d'une connexion n'est pas une bonne pratique.
Oded
11
-1 La réponse est plutôt trompeuse. Créer une connexion par requête est une très mauvaise idée. Vous voulez probablement dire "récupérer une nouvelle connexion pour chaque requête à partir du pool de connexions" - mais ce n'est pas la même chose que créer une connexion.
Sleske
1
@sleske - En quoi est-ce différent de la réponse de pdr?
Oded
3
@Oded: Ah, je vois. Dans .NET, les appels SqlConnection.Open()utiliseront toujours de manière transparente le regroupement de connexions. Donc, la différence entre "ouvrir une connexion" et "extraire une connexion d'un pool" n'existe pas. Mon malentendu. J'ai pris la liberté de modifier une petite explication dans la question et de reprendre le vote.
Sleske
2
@ eaglei22 - cela devrait certainement être le cas (voir docs.microsoft.com/en-us/dotnet/framework/data/adonet/… ). En règle générale, vous souhaiterez renvoyer la connexion au pool dès que possible. Toutefois, si vous émettez plusieurs requêtes en séquence, il peut être préférable de réutiliser une connexion comme vous le suggérez. Vous devez tester et voir quelle approche est la meilleure pour vous (je ne sais pas quels critères vous utilisez - vérifiez les deux méthodes et voyez l’effet sur les mesures que vous avez choisies).
Oded
0

Rappelez-vous tout cela dans le contexte de l'écosystème .Net.

Les développeurs veulent parfois "optimiser" leur code pour réutiliser leurs objets de connexion. Compte tenu du contexte de cette question, il s’agit presque toujours d’une erreur.

ADO.Net possède une fonctionnalité appelée Pooling de connexion . Lorsque vous créez et ouvrez un nouvel objet de connexion, vous demandez réellement une connexion à un pool. Lorsque vous fermez une connexion, vous la renvoyez à la piscine.

Il est important de comprendre les objets que nous utilisons directement dans le code: SqlConnection, MySQLConnection, OleDbConnectio, etc, sont tous à enrubanneuse autour d' une véritable connexion sous - jacente gérée par ADO.Net et les connexions réelles ADO.Net sont beaucoup plus « lourd » et plus cher du point de vue de la performance. Ce sont ces objets sous-jacents qui suscitent des inquiétudes telles que l'authentification, le transit sur le réseau, le cryptage, et ces éléments dépassent de loin la faible quantité de mémoire de l'objet que vous voyez réellement dans votre propre code.

Lorsque vous essayez de réutiliser votre objet de connexion, vous empêchez ADO.Net de gérer efficacement les connexions sous-jacentes importantes. Vous gagnez en efficacité dans les petites choses au détriment des choses beaucoup plus grandes.

La réutilisation d'une connexion via une application ou une demande http peut également vous obliger à sérialiser accidentellement un élément qui pourrait sinon être exécuté en parallèle et à devenir un goulot d'étranglement des performances. J'ai vu cela se produire dans de vraies applications.

Dans le cas de l'exemple de page Web ici, où vous ne gardez au moins que la petite connexion pendant la durée d'une requête / réponse http unique, vous pourriez gagner encore en efficacité en évaluant les requêtes que vous exécutez dans votre pipeline de requêtes et en essayant d'obtenir réduisez le nombre de requêtes distinctes à la base de données (astuce: vous pouvez soumettre plusieurs requêtes dans une seule chaîne SQL et utiliser DataReader.NextResult()ou vérifier différentes tables de manière DataSetà les déplacer).

En d'autres termes, plutôt que de penser à réutiliser une connexion pour une application ou une requête http par rapport à une connexion par requête, pensez en termes d'une connexion pour chaque appel à la base de données ... à chaque aller-retour. Essayez ensuite de minimiser le nombre de connexions en minimisant le nombre de ces voyages. De cette façon, vous pouvez atteindre les deux objectifs.


Mais ce n'est qu'un type d'optimisation. Il y a aussi l'optimisation du temps de programmation et la réutilisation efficace du code. Les développeurs ne veulent pas écrire le même code standard, encore et encore, juste pour obtenir un objet de connexion ouvert et prêt à être utilisé. Ce n'est pas seulement fastidieux, c'est un moyen d'introduire des bogues dans un programme.

Même ici, cependant, il est généralement préférable d’avoir une connexion par requête (ou aller-retour). Il existe d'autres modèles que vous pouvez utiliser pour éviter de réécrire le même code standard. Voici un exemple que j'aime bien, mais il y en a beaucoup d'autres.

Joel Coehoorn
la source
Je suis en retard pour cette soirée, mais je pense que cette réponse couvre quelques points importants :)
Joel Coehoorn