Connessioni Persistenti ai Database

Connessioni persistenti sono collegamenti che non vengono chiusi quando l'esecusione di uno script viene terminata. Quando è richiesta una connessione persistente, PHP controlla se esiste già una identica connessione persistente (che è rimasta aperta da prima) - e se esiste, la usa. Se non esiste, crea il collegamento. Una connessione 'identica' è una connessione aperta verso lo stesso host, con lo stesso username e la stessa password (dove applicabile).

Chi non ha molta familiarità con il modo in cui lavorano i server web e di come essi distribuiscano il carico potrebbero confondere le connessioni permanenti per ciò che esse non sono. In particolare, non danno la possibilità di aprire 'sessioni utente' sullo stesso collegamento, non danno la possibilità di gestire una transazione in maniera efficiente e sopratutto non fanno molte altre cose. Infatti, per essere molto chiari su questo punto, le connessioni persistenti non hanno nessuna funzionalià che non era disponibile con le loro omonime non-persistenti.

Perché?

Questo ha a che fare con il modo in cui i server web operano. Ci sono tre modi in cui un server web può utilizzare PHP per generare le pagine web.

Il primo metodo è quello di usare il PHP come un "wrapper" (involucro) CGI. Quando viene eseguito in questa modalità, per ogni pagina che viene richiesta al server web che contenga del codice PHP, viene creata e, alla fine dell'esecuzione, distrutta, una istanza dell'interprete PHP. Poiché viene distrutta alla fine di ogni richiesta, qualunque risorsa abbia acquisito (come ad esempio un collegamento ad un server di database SQL) verrà anch'essa distrutta. In questo caso, non vi è nessun guadagno nell'usare le connessioni persistenti -- semplicemente esse non persistono.

Il secondo, e più popolare, metodo è quello di eseguire il programma PHP come modulo in un server web multiprocesso, cosa che attualmente include solo Apache. Un server multiprocesso ha tipicamente un processo (il padre) che coordina un insieme di processi (i suoi figli) che sono quelli che generano le pagine web. Quando arriva una richiesta da parte di un client, questa è passata ad uno dei figli che in quel momento non è già occupato a servire un altro client. Questo significa che quando lo stesso client effettua una seconda richiesta al server, esso potrà essere servito da un diverso processo figlio rispetto a quello della prima volta. Quando si aprono delle connessioni persistenti, ciascuna pagina successiva che richiede dei servizi SQL, può riutilizzare la connessione al server SQL precedente.

L'ultimo metodo è quello di usare il PHP come una plug-in per un server web multithread. Attualmente PHP 4 supporta ISAPI, WSAPI e NSAPI (su piattaforma Windows), i quali permettono di usare PHP come una plug-in sui server web multithread come FastTrack (iPlanet) di Netscape, Internet Information Server (IIS) di Microsoft e WebSite Pro di O'Reilly. Il comportamento è essenzialmente lo stesso che si ha nel modello multiprocesso descritto prima.

Se le connessioni persistenti non hanno nessuna funzionalità aggiuntiva, perch´ usarle?

La risposta, in questo caso è estremamente semplice: efficienza. Le connessioni persistenti sono utili se il carico di lavoro necessario per aprire una connessione al server SQL è alto. Che il carico sia molto alto o meno dipende da molti fattori. Quali, il tipo di database che si utilizza, il fatto che esso si trovi sulla stessa macchina sulla quale si trova il server web, quanto carico di lavoro ha la macchina sulla quale si trova il server SQL, e molte altre ragioni. Il fatto importante è che se il carico di lavoro necessario per aprire le connessioni è alto, le connessioni persistenti possono aiutare in maniera considerevole. Fanno in modo che il processo figlio si colleghi semplicemente una volta durante la sua intera vita, invece di collegarsi ogni volta che processa una pagina che richiede una connessione al server SQL. Questo significa che per ogni figlio che ha aperto una connessione persistente, si avrà una nuova connessione persistente aperta verso il server. Per esempio, se si hanno 20 diversi processi figlio che eseguono uno script che crea una connessione persistente al server SQL server, si avranno 20 diverse connessioni al server SQL, una per ogni figlio.

Si fa notare, tuttavia, che questo può avere degli svantaggi se si fa uso di un database che ha un limite al numero di connessioni, minore rispetto al numero delle connessioni persistenti dei procesi figlio. Se per esempio di usa un database con 16 connessioni simultanee, e durante un periodo di intensa attività del web server, 17 processi figlio cercano di collegarsi, uno non sarà in grado di farlo. Se nei vostri script ci sono bug che non permettono alle connessioni di chiudersi in maniera regolare (come ad esempio un loop infinito), un database con sole 16 connessioni diventerà rapidamente saturo. Fare riferimento alla documentazione del database per informazioni su come gestire connessioni abbandonate o inattive.

Avviso

Ci sono un paio di altri caveat da tenere in considerazione quando si usano le connessioni persistenti. Uno è che quando si usa il table locking su una connessione persistente, se lo script, per una qualunque ragione non è in grado di rimuovere il blocco, allora i successivi script che useranno la stessa connessione rimarranno bloccati in maniera indefinita e potrebbe essre necessario riavviare il server httpd o il server database. Un altro è che quando si usano le transazioni, un transaction block verrà trasferito anche allo script successivo che usa la medesima connessione, se lo script in esecuzione termina prima che sia terminato il transaction block. In entrambi i casi, si può usare register_shutdown_function() per registrare una semplice funzione di pulizia per sbloccare le tabelle o effettuare il roll back delle transaczioni. Sarebbe meglio non dover affrontare il problema, semplicemente non usando le connessioni persistenti negli script che usano i lock delle tabelle o le transaczioni (si possono comunque usare in altre situazioni).

Sommario importante. Le connessioni persistenti sono state pensate per avere una mappatura uno-a-uno con le connessioni di tipo normale. Ciò significa che si dovrebbe sempre essere in grado di cambiare una connessione persistente con una connessione non-persistente, e che questo non dovrebbe cambiare il modo in cui lo script si comporta. Può (e probabilmente succederà) cambiare l'efficienza dello script, ma non il suo comportamento!

Vedere anche fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), ingres_pconnect(), msql_pconnect(), mssql_pconnect(), mysql_pconnect(), ociplogon(), odbc_pconnect(), oci_pconnect(), pfsockopen(), pg_pconnect(), e sybase_pconnect().

add a note add a note

User Contributed Notes 12 notes

up
7
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
4
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
3
ambrish at php dot net
3 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
3
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
1
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
1
whatspaz at g NO dot SPAM mail dot c o m
7 years ago
in response to web at nick, have you tried FLUSH PRIVILEGES. this should reload those privileges.
up
0
php at alfadog dot net
6 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
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
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
-2
jean_christian at myrealbox dot com
11 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
-2
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
-7
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