지속적인 데이터베이스 접속

지속적인 접속은 스크립트 수행이 종료되어도 연결을 끊지 않는 접속을 말한다. 지속적인 접속이 요청되면, PHP는 기존의 (이전에 열어 두었던) 동일한(identical) 지속적인 접속이 있는지 검사한다. 만약 있다면 기존의 것을 사용하고, 없다면 새로운 연결을 생성한다. '동일한' 접속이란 같은 호스트에 같은 사용자명과 같은 암호를 사용하여 열린 접속을 말한다.

가끔 웹서버의 작동과 작업의 할당에 대해 잘 알고 있지 못하는 사람들은 지속적인 접속이 사실은 별 것 아니라고 오해하기도 한다. 특히, 지속적인 접속이 동일한 연결에서 'user sessions'를 여는데 별 나을 것도 없다라던가, transaction을 효율적으로 처리하는 것도 아니다라던가, 혹은 다른 어떤 특별한 것을 하는 것도 아니라고 한다. 사실, 이런 말들에 대해 명백히 말하자면, 지속적인 접속은 비지속적인 접속에 비해 어떠한 기능적인 향상도 주지 못한다.

왜?

이것은 웹서버의 동작 방식에 따라 다른 효과를 낸다. 여러분의 웹서버가 웹 페이지를 만들기위해 PHP를 이용하는데는 3가지 방법이 있다.

첫 번째 방법은 PHP를 CGI "래퍼(wrapper)"의 형태로 사용하는 것이다. 이 방법의 경우, 웹서버에 매 PHP 페이지가 요구될 때 마다, PHP 인터프리터의 실행이 만들어지고 사리진다. 따라서 매 요구가 종료될 때마다 인터프리터의 실행이 종료되므로, 실행 중 만들었던(SQL 연결를 포함) 모든 자원은 실행 종료와 함께 해제된다. 이 경우 지속적인 접속을 사용하여 어떤 이득도 얻을 수 없다. 다르게 말하면 이 경우는 지속적인 접속을 해도 지속적이지 않다.

두 번째 방법은 가장 대중적인 방법인데, PHP를 다중프로세스 웹서버의 모듈로 사용하는 것이다. (현재는 아파치가 유일하다) 다중프로세스 서버는 보통 한 개의 부모 프로세스와, 이와 유기적으로 연결되어 웹 페이지를 실제로 만드는 작업을 하는 여러개의 자식 프로세스들을 가지고 있다. 클라이언트에서 요청이 왔을 때, 다른 클라이언트를 처리하고 있지 않은 자식 프로레스로 넘겨집니다. 이는 동일한 클라이언트가 서버에 두번째 요청을 하였을 때, 처음과 다른 자식 프로세스에서 처리할 수 있다는 의미입니다. 지속적인 접속을 열면, SQL 서비스를 요구하는 모든 페이지에서 동일한 SQL 서버 접속을 재사용할 수 있습니다.

마지막 방법은 PHP를 멀티쓰레드 웹서버의 플러그인 형태로 작동시키는 것이다. 현재 PHP4는 윈도우 환경에서 ISAPI 혹은 WSAPI, NSAPI의 방법을 사용하여 Netscape FastTrack, Microsoft's Internet Information Server (IIS), O'Reilly's WebSite Pro 등의 멀티쓰레드 웹서버에서 플러그인으로 동작한다. 이 동작은 앞에서 설명한 다중프로세스 모델과 동일합니다.

지속적인 접속이 실제로 어떠한 기능적인 향상도 주지 못한다면, 이것을 사용해 어떤 이점이 있나요?

이것에 대한 간단한 답은 효율성이다. 지속적인 접속은 SQL 서버와의 연결을 만드는 것에 따른 overhead가 클 경우에 유용하다. 이 overhead는 많은 요인에 따라 커지기도 하고 작아지기도 한다. 어떤 종류의 데이터베이스인가? 웹서버와 같은 컴퓨터에 데이터베이스 서버가 있는가? SQL 서버가 어떻게 사용되고 있는가? 등에 따라 크게 달라진다. 접속에 따른 overhead가 클 경우에 지속적인 접속은 적지 않은 도움을 줄 것이다. 이것은 자식 process에서 SQL 서버에 접속을 요청할 때 마다 접속을 만드는 대신, 이 프로세스가 종료될 때 까지 살아있는 한 개의 접속 만을 사용한다. 이것은 모든 지속적인 접속을 사용한 프로세스는, 그에 해당하는 한 개의 지속적인 접속을 가지고 있다는 것을 의미한다. 예를 들어 SQL 서버에 대하여 지속적인 접속을 사용하는 스크립트를 실행하였던 20개의 다른 자식 프로세스가 있다면, 아마도 각각의 자식 프로세스에 대해 1개씩, 20개의 SQL 접속이 있을 것이다.

이 방법은 지속적인 접속의 개수가 데이타베이스 서버가 허용하는 접속수를 초과해서 설정되어 있는 경우 문제가 될 수 있다. 만약 데이타베이스가 16개의 동시 접속을 허용하고, 이 서버 세션들이 모두 사용중이면, 17번째 thread는 연결을 시도하다가 실패할 것이다. 만약 여러분이 만든 스크립트에 이런 경우에 대비한 특별한 대책이 없이 재시도를 반복하다보면 가능한 모든 connection을 사용하여 복구할 수 없게 된다. 이런 abandoned 혹은 idle connection을 다루는 자세한 설명은 데이타베이스 문서를 참조하기 바란다.

Warning

지속적인 접속을 사용할때 두가지 추가적인 경고를 염두에 두고 있어야 한다 한가지는 지속적인 접속에서 테이블 락킹(locking)을 사용할때이다. 스크립트가 어떤 이유로 락을 풀수 없을때, 같은 접속을 사용하는 다음 스크립트는 무한정 block될것이고 이 경우에는 httpd 서버나 데이터베이스 서버를 재시작시켜야 할수도 있다. 다른 한가지는 트랜잭션을 사용할때이다. 트랜잭션 블록은 그 트랜잭션 블록이 수행되기 전에 스크립트가 수행을 종료하면 그 접속을 사용하는 다음 스크립트에 이월하게 된다. 각각의 경우에, register_shutdown_function()을 사용하여 테이블 unlock하거나 트랜잭션을 롤백하는 해제 함수를 등록 할수 있다. 이런 문제를 완전히 회피하기 위한 더 좋은 방법은 지속적인 접속을 사용하는 스크립트에서 테이블 락이나 트랜젝션을 사용하지 않는 것이다 (어느 곳에서는 그것을 사용할수 있다)

중요한 언급 한가지! 지속적인 접속은 일반적인 접속에 일대일로 대응되도록 설계되었다. 이것은 스크립트의 다른 부분은 그대로 두고, 언제라도 비지속적인 접속을 지속적인 접속으로 대치할 수 있다는 것을 의미한다. 이기능으로 아마도 스크립트의 동작이 아니라 효율을 향상시킬 수도 있을 것이다.

fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), ingres_pconnect(), msql_pconnect(), mssql_pconnect(), mysql_pconnect(), ociplogon(), odbc_pconnect(), oci_pconnect(), pfsockopen(), pg_pconnect(), sybase_pconnect() 참고.

add a note add a note

User Contributed Notes 13 notes

up
16
php at alfadog dot net
10 years 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
6
ynzhang from lakeheadu canada
15 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
3
christopher dot jones at oracle dot com
16 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
1
Tom
14 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
0
ambrish at php dot net
13 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
-2
pacerier at gmail dot com
8 years ago
Did anyone else notice that the last paragraph contradicts everything above it?

( cached page: https://archive.is/ZAOwy )
up
-1
andy at paradigm-reborn dot com
17 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
fabio
18 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
-10
RQuadling at GMail dot com
18 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
-11
whatspaz at g NO dot SPAM mail dot c o m
17 years ago
in response to web at nick, have you tried FLUSH PRIVILEGES. this should reload those privileges.
up
-13
jean_christian at myrealbox dot com
21 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
-22
aaryal at foresightint dot com
20 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
-33
jorgeleon85 at gmail dot com
13 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