Datenbankverbindungen herstellen - Einmal oder für jede Abfrage?

101

Momentan erstelle ich eine Datenbankverbindung, wenn meine Webseite zum ersten Mal geladen wird. Ich verarbeite dann die Seite und führe alle Abfragen für diese Verbindung aus. Ist dies die beste Methode, oder sollte bei jeder Abfrage eine Datenbankverbindung hergestellt werden?

ps Es ist für mich sinnvoller, eine Verbindung zu erstellen und zu verwenden, aber ich weiß nicht, ob dies andere Probleme verursachen kann.

Ich verwende C # (ASP.NET) mit MSSQL.

webnoob
quelle

Antworten:

124

Wenn Sie eine pro Abfrage / Transaktion erstellen, ist es viel einfacher, das "Schließen" der Verbindungen zu verwalten.

Ich kann verstehen, warum der gesunde Menschenverstand vorschreibt, dass Sie eine öffnen und diese durchgehend verwenden müssen, aber Sie werden Probleme mit unterbrochenen Verbindungen und Multithreading haben. Ihr nächster Schritt wird also darin bestehen, einen Pool mit etwa 50 Verbindungen zu eröffnen und alle Verbindungen offen zu halten, um sie unterschiedlichen Prozessen zuzuführen. Und dann werden Sie feststellen, dass das .NET Framework genau dies bereits für Sie erledigt .

Wenn Sie eine Verbindung öffnen, wenn Sie sie benötigen, und wenn Sie fertig sind, wird die Verbindung dadurch nicht geschlossen, sondern nur an den Verbindungspool zurückgegeben, um sie erneut zu verwenden.

pdr
quelle
Hab gerade diesen Artikel gelesen, als du ihn gepostet hast :) Danke.
Webnoob
2
Die Webseite, auf die Sie verlinkt haben, ist spezifisch für SQL Server. Bietet .NET auch ein automatisches Pooling, wenn eine Verbindung zu anderen Datenbanken hergestellt wird, z. B. Oracle, SQLite, MySQL?
Briddums
@briddums - Ich denke, das hängt vom Anschluss ab. .Net bietet beispielsweise keinen MySQL-Connector. Es wird von MySql geschrieben und gepflegt. Und obwohl es funktioniert, war die frühere Implementierung meiner Erfahrung nach alles andere als fehlerfrei.
ZweiBlumen
1
@briddums: Hängt von der Provider-Assembly ab. Ich bin mir sicher, dass sowohl die Oracle-Implementierung von Microsoft als auch die eigene Oracle-Implementierung das Verbindungspooling unterstützen, da ich sie verwendet habe. Ich habe gehört, dass es eine MySql-Version gibt, und ich würde erwarten, dass die Anbieter in Spring.NET das Pooling unterstützen, aber Sie sollten lieber nach dem Anbieter suchen oder ihn direkt fragen, als mich zu fragen.
pdr
1
Es sollte bekannt sein, dass das Öffnen, Ausführen und Freigeben einer Verbindung, auch in einer Schleife, genauso schnell und manchmal SCHNELLER ist als das einmalige Öffnen und Schleifen der Abfrage. Immer einfach entsorgen. Es ist sicherer und SCHNELL. Machen Sie sich keine Sorgen über den Aufwand, eine Verbindung vom Pool zu erhalten - es ist so trivial.
smdrager
38

Es wird empfohlen, eine Verbindung pro Abfrage zu erstellen. Bei der Anzeige von Daten werden alle erforderlichen Daten auf einmal von der Abfrage übernommen .

Hintergrundinformation:

In .NET wird beim Aufrufen SqlConnection.Open()standardmäßig immer das Verbindungspooling transparent verwendet (siehe "Verwenden des Verbindungspoolings mit SQL Server" auf MSDN). Sie können also einfach eine neue Verbindung mit greifen Open()und anrufen, Close()wenn Sie fertig sind, und .NET wird das Richtige tun.

Beachten Sie, dass ohne Verbindungspooling eine Verbindung pro Abfrage eine sehr schlechte Idee wäre, da das Erstellen von realen Datenbankverbindungen sehr kostspielig sein kann (Authentifizierung, Netzwerk-Overhead usw.) und die Anzahl der gleichzeitig geöffneten Verbindungen in der Regel sehr begrenzt ist.

Oded
quelle
7
@webnoob - Da .NET Connection Pooling verwendet, ist dies nicht der Fall. Der Grund dafür ist, dass Verbindungen geschlossen, neu zugewiesen usw. werden können. Die Wiederverwendung einer Verbindung ist daher keine gute Praxis.
Oded
11
-1 Die Antwort ist eher irreführend. Das Erstellen einer Verbindung pro Abfrage ist eine sehr schlechte Idee. Was Sie wahrscheinlich meinen, ist "eine neue Verbindung für jede Abfrage aus dem Verbindungspool abrufen" - aber das ist nicht dasselbe wie das Erstellen einer Verbindung.
Sleske
1
@sleske - Wie unterscheidet sich das von der Antwort von pdr?
Oded
3
@Oded: Ah, ich verstehe. In .NET wird beim Aufrufen SqlConnection.Open()immer transparentes Verbindungspooling verwendet. Der Unterschied zwischen "Verbindung öffnen" und "Verbindung aus einem Pool starten" besteht also nicht. Mein Missverständnis. Ich habe mir erlaubt, eine kleine Erklärung zu der Frage zu redigieren, und die Abstimmung zurückgenommen.
Sleske
2
@ eaglei22 - das sollte es auf jeden Fall tun (siehe docs.microsoft.com/en-us/dotnet/framework/data/adonet/… ). Im Allgemeinen möchten Sie die Verbindung zum Pool so bald wie möglich zurückgeben. Wenn Sie jedoch mehrere Abfragen nacheinander ausführen, ist es möglicherweise besser, eine Verbindung wie vorgeschlagen wiederzuverwenden. Sie müssten testen und herausfinden, welcher Ansatz für Sie am besten geeignet ist (ich weiß nicht, welche Kriterien Sie verwenden - überprüfen Sie beide Möglichkeiten und überprüfen Sie die Auswirkung auf die von Ihnen ausgewählten Metriken).
Oded
0

Denken Sie daran, dass dies alles im Kontext des .Net-Ökosystems steht.

Entwickler möchten manchmal ihren Code "optimieren", um ihre Verbindungsobjekte wiederzuverwenden. Angesichts des Zusammenhangs dieser Frage ist dies fast immer ein Fehler.

ADO.Net verfügt über eine Funktion namens Verbindungspooling . Wenn Sie ein neues Verbindungsobjekt erstellen und öffnen, fordern Sie in Wirklichkeit eine Verbindung aus einem Pool an. Wenn Sie eine Verbindung schließen, geben Sie sie an den Pool zurück.

Es ist wichtig, die Objekte zu verstehen, die wir direkt im Code verwenden: SqlConnection, MySqlConnection, OleDbConnectio usw. sind alles nur Wrapper um eine echte zugrunde liegende Verbindung, die von ADO.Net verwaltet wird, und die echten ADO.Net-Verbindungen sind viel "schwerer" und teurer vom Standpunkt der Leistung. Es sind diese zugrunde liegenden Objekte, die Probleme mit der Authentifizierung, dem Netzwerktransit und der Verschlüsselung haben, und diese Dinge überwiegen bei weitem die geringe Menge an Speicher in dem Objekt, die Sie tatsächlich in Ihrem eigenen Code sehen.

Wenn Sie versuchen, Ihr Verbindungsobjekt wiederzuverwenden, unterbrechen Sie die Fähigkeit von ADO.Net, die wichtigen zugrunde liegenden Verbindungen effektiv zu verwalten. Sie erzielen Effizienz im Kleinen auf Kosten des Großen.

Die erneute Verwendung einer Verbindung über eine Anwendung oder eine http-Anforderung hinweg kann Sie auch dazu zwingen, versehentlich etwas zu serialisieren, das ansonsten möglicherweise parallel ausgeführt werden kann, und zu einem Leistungsengpass führen. Ich habe dies in realen Anwendungen gesehen.

Im Fall des hier gezeigten Webseitenbeispiels, in dem Sie zumindest die kleine Verbindung für die Dauer einer einzelnen http-Anforderung / Antwort beibehalten, können Sie noch effizienter werden, indem Sie auswerten, welche Abfragen in Ihrer Anforderungspipeline ausgeführt werden, und versuchen, diese abzurufen Sie müssen nur so wenige separate Anforderungen wie möglich an die Datenbank senden (Hinweis: Sie können mehr als eine Abfrage in einer einzelnen SQL-Zeichenfolge senden und DataReader.NextResult()verschiedene Tabellen in a verwenden oder überprüfen DataSet, um zwischen ihnen zu wechseln).

Mit anderen Worten, anstatt zu überlegen, ob eine Verbindung für eine Anwendung oder eine HTTP-Anforderung oder eine Verbindung pro Abfrage erneut verwendet werden soll, sollten Sie bei jedem Aufruf der Datenbank ... für jeden Roundtrip eine Verbindung angeben. Versuchen Sie dann, die Anzahl der Verbindungen zu minimieren, indem Sie die Anzahl dieser Trips minimieren. Auf diese Weise können Sie beide Ziele erreichen.


Das ist aber nur eine Art von Optimierung. Außerdem wird die Programmierzeit optimiert und eine effektive Wiederverwendung des Codes erreicht. Entwickler möchten nicht immer wieder denselben Code schreiben, um ein offenes und einsatzbereites Verbindungsobjekt zu erhalten. Es ist nicht nur mühsam, sondern auch eine Möglichkeit, Fehler in ein Programm einzufügen.

Auch hier ist es im Allgemeinen besser, eine Verbindung pro Abfrage (oder Roundtrip) zu haben. Sie können auch andere Muster verwenden, um zu vermeiden, dass derselbe Kesselschildcode erneut geschrieben wird. Hier ist ein Beispiel, das ich mag, aber es gibt viele andere.

Joel Coehoorn
quelle
Ich bin zu spät zu dieser Party, aber ich denke, diese Antwort deckt einige wichtige Punkte ab :)
Joel Coehoorn