Persistente Datenbankverbindungen

Persistente Verbindungen sind Verbindungen, die nach Abarbeitung des Skriptes nicht geschlossen werden. Wenn eine persistente Verbindung angefordert wird, prüft PHP zuerst, ob bereits eine identische persistente Verbindung (die vielleicht vorher offen geblieben ist) existiert und benutzt sie in diesem Fall. Sollte keine Verbindung existieren, wird eine hergestellt. Eine 'identische' Verbindung ist eine Verbindung, die zu dem gleichen Host mit dem gleichen Usernamen und Passwort hergestellt wurde.

Wer nicht durchgängig mit der Art und Weise vertraut ist, wie Webserver arbeiten und die Last verteilen, könnte missverstehen, wofür persistente Verbindungen gedacht sind. Im Besonderen bieten sie keine Möglichkeit, 'Benutzersitzungen' über die gleiche Verbindung zu öffnen und keine Möglichkeit, eine Transaktion effizient aufzubauen, und sie können auch viele andere Dinge nicht. Um absolute Klarheit zu schaffen: Persistente Verbindungen bieten keine Funktionalität, die nicht auch von nicht-persistenten Verbindungen bereitgestellt wird.

Warum?

Das hat mit der Arbeitsweise von Webservern zu tun. Es gibt drei Möglichkeiten, wie ein Webserver PHP zur Generierung von Webseiten einsetzen kann.

Die erste Methode ist, PHP als CGI-'Wrapper' zu benutzen. Wenn diese Methode eingesetzt wird, wird für jede Anfrage nach einer PHP-Seite vom Webserver eine Instanz des PHP- Interpreters gestartet und anschließend wieder beendet. Durch die Beendigung des Interpreters nach abgeschlossener Anfrage werden alle Ressourcen, auf die zugegriffen wurde (wie beispielsweise eine Verbindung zu einem SQL- Datenbankserver) wieder geschlossen. In diesem Fall erreicht man nichts, wenn man persistente Verbindungen benutzt - sie sind eben nicht beständig.

Die zweite und populärste Methode ist der Einsatz von PHP als Modul in einem Multiprozess-Webserver, was momentan nur auf den Apache zutrifft. Typischerweise hat ein Multiprozess-Webserver einen Prozess (den 'Eltern' Prozess), der einen Satz weiterer Prozesse (die 'Kinder') koordiniert, welche die eigentliche Arbeit des Bereitstellens der Seiten übernehmen. Jede Anfrage, die von einem Client erfolgt, wird an einen untergeordneten Prozess, der noch keine andere Anfrage bearbeitet, weitergereicht. Das bedeutet, dass eine zweite Anfrage des gleichen Clients an den Server unter Umständen von einem anderen untergeordneten Prozess als die erste Anfrage bearbeitet wird. Wurde eine persistente Verbindung einmal geöffnet kann jede danach folgenge Seite innerhalb des gleichen Prozesses diese bereits zum Server bestehende Verbindung weiter verwenden.

Die letzte Methode ist, PHP als Plug-in für einen Multithread- Webserver zu benutzen. Derzeit bietet PHP 4 Unterstützung für ISAPI, WSAPI und NSAPI (unter Windows), wodurch die Nutzung von PHP mit Multithread-Serven wie Netscape Fast Track (iPlanet), Microsoft Internet Information Server (IIS) und O'Reilly's WebSite Pro ermöglicht wird. Das Verhalten entspricht im wesentlichen dem oben beschriebenen Multiprozess-Modell.

Wozu dienen persistente Verbindungen, wenn sie keine zusätzliche Funktionalität bieten?

Die Antwort ist außerordentlich einfach: Effizienz. Persistente Verbindungen sind nützlich, wenn der Aufwand für das Herstellen einer Verbindung zu einem SQL-Server hoch ist. Ob dies der Fall ist oder nicht, hängt von vielen Faktoren ab - zum Beispiel, um welche Datenbank es sich handelt, ob sie auf dem gleichen Rechner wie der Webserver läuft oder welche Last die SQL-Maschine zu bewältigen hat usw. Grundsätzlich gilt, dass, wenn viele Verbindungen hergestellt werden müssen, persistente Verbindungen außerordentlich hilfreich sind. Sie veranlassen den untergeordneten Prozess, sich während seiner gesamten Lebensdauer lediglich einmal mit dem SQL-Server zu verbinden, anstatt bei jedem Aufruf einer Seite, die eine Verbindung benötigt. Das heißt, dass jeder untergeordnete Prozess, der eine persistente Verbindung öffnet, seine eigene dauerhafte Verbindung zum Server hat. Bei 20 untergeordneten Prozessen, die ein Skript ausführen, das eine persistente Verbindung zum SQL-Server herstellt, hat man beispielsweise 20 verschiedene Verbindungen zum SQL-Server - eine für jeden untergeordneten Prozess.

Beachten Sie jedoch, dass dies auch ein paar Nachteile haben kann, wenn Sie eine Datenbank mit limitierten Verbindungen benutzen, welche durch persistente Verbindungen überschritten werden. Wenn Ihre Datenbank ein Limit von 16 gleichzeitigen Verbindungen hat, und aufgrund einer stark ausgelasteten Server-Session 17 Kind-Prozesse versuchen, eine Verbindung herzustellen, wird es einem nicht gelingen. Sollten in Ihren Skripten Fehler bestehen, welche das Schließen der Verbindungen nicht erlauben (wie z.B. Endlosschleifen), kann das eine Datenbank mit mit nur 16 Verbindungen sehr schnell überschwemmen. Konsultieren Sie die Dokumentation Ihrer Datenbank bezüglich der Behandlung von aufgegebenen Verbindungen oder Verbindungen im Leerlauf.

Warnung

Sie sollten sich zur Vorsicht noch ein paar Gedanken machen, wenn Sie persistente Verbindungen benutzen. Einer ist, wenn Sie über eine persistente Verbindung Tabellen sperren und das Skript diese Sperre aus welchem Grund auch immer nicht mehr aufheben kann, nachfolgende Skripte, welche die selbe Verbindung benutzen, blockieren und den Neustart von entweder dem Webserver oder dem Datenbankserver verlangen. Ein weiterer ist, dass wenn Sie Transaktionen benutzen, ein Transaktionsblock zu dem nächsten die Verbindung nutzenden Skript übertragen wird, wenn die Ausführung des Skriptes vor dem Transaktionsblock gestoppt wird. In jedem Fall können Sie register_shutdown_function() benutzen, um eine einfache Funktion zu registrieren, welche Ihre Tabellen wieder entsperrt, oder Ihre Transaktionen zurückstellt. Besser ist es, wenn Sie dieses Problem gänzlich vermeiden, indem keine persistenten Verbindungen in Skripten benutzen, welche Tabellen sperren oder Transaktionen verwenden (Sie können sie immer noch anderswo benutzen).

Eine wichtige Zusammenfassung. Persistente Verbindungen wurden entwickelt, um eins-zu-eins Abbildungen auf reguläre Verbindungen zu haben. Das heißt, dass man immer in der Lage sein sollte, die persistenten Verbindungen durch nicht-persistente zu ersetzten, ohne dass dies den Skriptablauf verändert. Es kann (und wird vermutlich auch) die Effizienz des Skriptes beeinflussen, aber nicht dessen Verhalten.

Siehe auch fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), msql_pconnect(), mssql_pconnect(), mysql_pconnect(), ociplogon(), odbc_pconnect(), ora_plogon(), pfsockopen(), pg_pconnect() und sybase_pconnect().

add a note add a note

User Contributed Notes 12 notes

up
5
fabio
8 years ago
You can in fact provide a port for the connection, take a look at http://de2.php.net/manual/en/function.mysql-pconnect.php#AEN101879

Just use "hostname:port" for the server address.
up
4
christopher dot jones at oracle dot com
7 years ago
For the oci8 extension it is not true that " [...] when using transactions, a transaction block will also carry over to the next script which uses that connection if script execution ends before the transaction block does.".  The oci8 extension does a rollback at the end scripts using persistent connections, thus ending the transaction.  The rollback also releases locks. However any ALTER SESSION command (e.g. changing the date format) on a persistent connection will be retained over to the next script.
up
3
ambrish at php dot net
4 years ago
In IBM_DB2 extension v1.9.0 or later performs a transaction rollback on persistent connections at the end of a request, thus ending the transaction. This prevents the transaction block from carrying over to the next request which uses that connection if script execution ends before the transaction block does.
up
1
php at alfadog dot net
10 months ago
One additional not regarding odbc_pconnect  and possibly other variations of pconnect:

If the connection encounters an error (bad SQL, incorrect request, etc), that error will return with  be present in odbc_errormsg for every subsequent action on that connection, even if subsequent actions don't cause another error.

For example:

A script connects with odbc_pconnect.
The connection is created on it's first use.
The script calls a query "Select * FROM Table1".
Table1 doesn't exist and odbc_errormsg contains that error.

Later(days, perhaps), a different script is called using the same parameters to odbc_pconnect.
The connection already exists, to it is reused.
The script calls a query "Select * FROM Table0".
The query runs fine, but odbc_errormsg still returns the error about Table1 not existing.

I'm not seeing a way to clear that error using odbc_ functions, so keep your eyes open for this gotcha or use odbc_connect instead.
up
1
RQuadling at GMail dot com
8 years ago
If you have multiple databases on the same server AND you are using persistent connections, you MUST prefix all the table names with the specific database name.

Changing the database using the xxx_select_db functions alters the database for the connection for all users who are sharing that connection (assuming PHP is running shared and not CGI/CLI).

If you have 2 databases (live and archive) and your script is talking to both, you cannot use 2 persistent connections and change the database for each one.

Internally, persistent connections are used even if you do not specify that you want to use persistent connections. This is why new_link was added to mysql_connect/mssql_connect (PHPV4.2.0+).
up
0
ynzhang from lakeheadu canada
5 years ago
It seems that using pg_pconnect() will not persist the temporary views/tables. So if you are trying to create temporary views/tables with the query results and then access them with the next script of the same session, you are out of luck. Those temporary view/tables are gone after each PHP script ended. One way to get around this problem is to create real view/table with session ID as part of the name and record the name&creation time in a common table. Have a garbage collection script to drop the view/table who's session is expired.
up
-1
whatspaz at g NO dot SPAM mail dot c o m
8 years ago
in response to web at nick, have you tried FLUSH PRIVILEGES. this should reload those privileges.
up
-3
Tom
4 years ago
There's a third case for PHP: run on a fastCGI interface. In this case, PHP processes are NOT destroyed after each request, and so persistent connections do persist. Set PHP_FCGI_CHILDREN << mysql's max_connections and you'll be fine.
up
-4
andy at paradigm-reborn dot com
7 years ago
To those using MySQL and finding a lot of leftover sleeping processes, take a look at MySQL's wait_timeout directive. By default it is set to 8 hours, but almost any decent production server will have been lowered to the 60 second range. Even on my testing server, I was having problems with too many connections from leftover persistent connections.
up
-7
jean_christian at myrealbox dot com
12 years ago
If anyone ever wonders why the number of idle db process (open connections) seems to grow even though you are using persistent connections, here's why:

"You are probably using a multi-process web server such as Apache. Since
database connections cannot be shared among different processes a new
one is created if the request happen to come to a different web server
child process."
up
-7
aaryal at foresightint dot com
10 years ago
this one bit quite a bit of chunk out of my you-know-what. seems like if you're running multiple database servers on the same host (for eg. MySQL on a number of ports) you can't use pconnect since the port number isn't part of the key for database connections. especially if you have the same username and password to connect to all the database servers running on different ports. but then it might be php-MySQL specific. you might get a connection for an entirely different port than the one you asked for.
up
-13
jorgeleon85 at gmail dot com
3 years ago
I've been looking everywhere for a benchmark or at least comparison of the overhead used by oci_connect and oci_pconnect.
Just saying "oci_connect is slower because the overhead..." is not enough for me. For than I wrote a couple scripts to compare perfomance.
At the end I found out an average of 34% more time using a oci_connect than oci_pconnect, using a query of 50 rows and 100 columns.
Obviously this wasn't a real benchmark however it gives a simple idea of the efficiency of each function.
To Top