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.
Bölüm 23. Kalıcı Veritabanı Bağlantıları
Kalıcı bağlantılar, betiğiniz sonlandığında kapatılmayan SQL bağlantılarına denir. Kalıcı bir bağlantı istendiğinde, PHP daha önceden tamamen aynı özelliklerde başka bir kalıcı bağlantı açılıp açılmadığına bakar (daha önceden kalan) - ve eğer varsa, onu kullanır. Eğer yoksa, yeni bağlantı kurar. 'Tamamen aynı' bağlantılar, aynı sunucuya, aynı kullanıcı ismi ve (gerekliyse) şifreyle açılmış bağlantılardır.
HTTP sunucularının çalışma mantığına aşina olmayanlar, kalıcı bağlantıları gerçekte olmadıkları şeyler sanabilirler. Özellikle, aynı SQL bağlantısı üzerinde 'kullanıcı oturumları' açmazlar, transaction'ları daha etkili bir şekilde yapmanızı sağlamazlar ve başka pek çok şeyi gerçekleştirmezler. Konu hakkında daha açık olmak gerekirse, kalıcı bağlantılar size kardeşleri kalıcı olmayan bağlantıların sunmadığı hiç bir ek özellik sunmazlar.
Neden?
Bu daha çok HTTP sunucularının çalışma mantığıyla alakalı. Sunucunun PHP'yi kullanarak web sayfaları oluşturmasının üç yöntemi var.
İlk yöntem PHP'yi CGI "sargısı" olarak kullanmak. Bu şekilde çalıştığında, sunucuya gelen her sayfa isteği için ayrı bir PHP yorumlayıcısı yaratılır ve yokedilir (PHP sayfaları için). İşlemler sonunda yokedildikleri için, yarattıkları her kaynak da (SQL sunucusuna bağlantılar gibi) onlarla birlikte yokolur. Bu durumda, kalıcı bağlantılar kurmayı denemekle elinize hiçbirşey geçmez -- basitçe, kalıcı olamazlar.
İkinci, ve en popüler, yöntem PHP'yi çok işlemli (multiprocess) bir sunucuda modül olarak kullanmak, şu an sadece Apache'de olduğu gibi. Çok işlemli bir sunucu genellikle bir ana işlemden (parent) ve onun kontrolündeki gerçekte işlemleri yapan çocuk işlemlerden (children) oluşur. Ne zaman bir alıcıdan istek gelse, istek o anda başka bir isteğe cevap vermeyen bir çocuk işleme devredilir. Bu demektir ki, aynı alıcı ikinci bir istek yolladığında, başka bir çocuk işlem tarafından karşılanabilir. Kalıcı bağlantıların sizin için burada yaptığı iş, her çocuk işlemin sadece ilk seferde SQL sunucusuna bağlanmasıdır. Başka bir sayfanın aynı bağlantıya ihtiyaç duyması durumunda önceden kurulmuş bağlantı kullanılır.
Son yöntem PHP'yi çok iş parçacıklı (multithreaded) sunucularda eklenti olarak kullanmak. Şu anda PHP 4'ün Netscape FastTrack (iPlanet), Microsoft Internet Information Server (IIS), ve O'Reilly Website Pro gibi çok iş parçacıklı sunucularda çalışmasını sağlayan ISAPI, WSAIP, ve NSAPI (Windows'ta) için desteği var. Bu çalışma şekli az önce anlatılan çok işlemli modelle aynı. SAPI desteğinin PHP 3'te olmadığına dikkat edin.
Eğer kalıcı bağlantıların ek özellikleri yoksa, neye yararlar?
Buradaki cevap oldukça basit -- etkinlik. Kalıcı bağlantılar, SQL sunucunuza yeni bağlantı açmak performans açısından hesaplı değilse çok işe yararlar. Performans hesaplılığı pek çok şeye bağlıdır. Örneğin, ne tür bir veritabanı olduğu, HTTP sunucusuyla aynı bilgisayarda olup olmayışı, SQL sunucusunun çalıştığı bilgisayarın işlem yoğunluğu ve benzeri. Sonuç şu ki, yeni bağlantı performansı düşükse, kalıcı bağlantılar işe yarar. Her çocuk işlemin her seferinde yeni bağlantı açması yerine hayatı boyunca sadece bir kere bağlantı yapmasını ve sürekli onu kullanmasını sağlarlar. Bu demektir ki, kalıcı bağlantı açan her çocuk işlemin kendisine ait SQL sunucusuna kalıcı bir bağlantısı olacaktır. Örneğin, 20 tane kalıcı bağlantı açan betik çalıştırmış farklı çocuk işlem varsa, SQL sunucusuna, her çocuk işlemden bir tane olmak üzere, 20 tane bağlantı olacaktır.
Ancak dikkat edin ki, SQL sunucusunun bağlantı limiti kalıcı bağlantılarla aşıldığında bunun bir takım götürüleri olacaktır. Eğer veritabanı sunucunuz ayni anda 16 bağlantıya izin veriyorsa, ve yoğun bir çalışma anında 17 çocuk işlem kalıcı bağlantı açmaya kalkarsa, bunlardan biri bağlantıyı açamaz. Eğer betiklerinizde bağlantıların kapanabilmesine olanak tanımayan hatalar varsa (kısır döngüler gibi), 32 bağlantıya izin veren bir veritabanı sunucusu çok çabuk bir şekilde kullanım dışı olur. Boş duran (idle) bağlantılarla nasıl ilgileneceğiniz konusunda veritabanınızın dökümanlarına başvurun.
| Uyarı |
Kalıcı bağlantı kullanırken akılda tutulması gereken birkaç ek götürü daha var. Örneğin kalıcı bir bağlantı üzerinden bir tablo kitlendiyse (LOCK), ve betik herhangi bir sebepten dolayı kilidi kaldıramıyorsa, ardısıra gelen ve aynı bağlantıyı kullanacak betikler süresiz olarak bloke olacak, ve sizin ya HTTP sunucusunu ya da veritabanı sunucusunu baştan çalıştırmanız gerekecektir. Başka bir götürü transaction kullanırken oluşabilir. Bir transaction bloğu, betiğin çalışma süresi bloğun ömründen kisaysa, bir sonraki betiğe taşınacaktır. İki durumda da register_shutdown_function() ile transaction'i geri alacak ya da tablo kilitlerini kaldıracak bir temizlik fonksiyonu kaydedebilirsiniz. Daha iyisi, problemleri tümüyle önlemek için tablo kilitleri veya transaction kullanan betiklerde kalıcı bağlantıları kullanmamaktır (başka yerlerde hala kullanabilirsiniz). |
Önemli bir özet. Kalıcı bağlantılar normal bağlantılarla birebir eşlenebilecek şekilde tasarlandı. Bu demektir ki her zaman kalıcı bağlantıları normal olanlarla değiştirebilirsiniz, ve bu betiklerin davranışlarını etkilemeyecektir. Betiklerin etkinliklerini belki değiştirebilirler, fakat davranışını değiştirmezler!
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.
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.
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.
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.
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.
in response to web at nick, have you tried FLUSH PRIVILEGES. this should reload those privileges.
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+).
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.
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.
This may only pertain to Apache/MySQL:
After several hours of wrestling with MySQL "Access denied" messages, I determined that persistent database connections don't necessarily reflect subsequent privilege changes.
I loaded a PHP script attempting a LOAD DATA statement, and got an "Access denied" error. I granted FILE privileges to the MySQL user, and was able to run LOAD DATA statements from the terminal, but still got "Access denied" from my PHP pages. When I switched from mysql_pconnect() to mysql_connect(), the problem went away; eventually I restarted apache to kill the persistent connection and switched back to mysql_pconnect(), and now everything works fine.
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."
Yes, with nonpersistent connections database connections last only while a database-related request is processed, thus reducing the load on the database server.
However, latency will be somewhat higher since a database connection must be opened before a request can be handeled.
