Conexões Persistentes com o Banco de Dados


Conexões Persistentes com o Banco de Dados

Conexões persistentes são conexões que não fecham quando a execução do seu script termina. Quando uma conexão persistente é requisitada, o PHP verifica se já existe uma conexão persistente idêntica (que foi mantida aberta anteriormente) - e, se ela existir, ele a usa. Se ela não existir, ele cria a conexão. Uma conexão 'idêntica' é uma conexão que foi aberta para o mesmo host, com o mesmo nome de usuário e a mesma senha (onde for aplicável).

Pessoas que não são totalmente familiarizadas com a maneira como servidores web trabalham e distribuem a carga podem confundir conexões persistentes com o que elas não são. Em particular, elas não dão a você a capacidade de abrir 'sessões de usuários' na mesma conexão, elas não dão a você a capacidade de construir uma transação eficientemente, e elas não fazem muitas outras coisas. De fato, para ser extremamente claro sobre o assunto, conexões persistentes não te dão nenhuma funcionalidade que não era possível com as suas correspondentes não-persistentes.

Por que?

Isso tem a ver com a maneira como os servidores web funcionam. Existem três maneiras em que seu servidor web pode utilizar PHP para gerar páginas.

O primeiro método é usar o PHP como um CGI "wrapper". Quando executado dessa maneira, uma instância do interpretador do PHP é criada e destruída para cada requisição de página (para uma página PHP) para o seu servidor web. Como ela é destruída após cada requisição, quaisquer recursos que ela adquirir (como uma conexão para um servidor de banco de dados SQL) são fechados quando ela é destruída. Nesse caso, você não ganha nada por tentar usar conexões persistentes -- elas simplesmente não persistem.

O segundo método, e mais popular, é rodar o PHP como um módulo em um servidor com multi-processos, que atualmente só inclue o Apache. Um servidor com multi-processos tipicamente tem um processo (o pai) que coordena uma série de processos (seus filhos) que realmente fazem o trabalho de servir as páginas web. Quando uma requisição chega de um cliente, ela é entregue à um dos filhos que já não estiver servindo outro cliente. Isso significa que quando o mesmo cliente faz uma segunda requisição para o servidor, ele pode ser atendido por um processo filho diferente do que da primeira vez. Ao abrir uma conexão persistente, cada página que requisitar serviços de SQL pode reutilizar a mesma conexão estabelecida ao servidor SQL.

O último método é usar o PHP como um plug-in para um servidor web multithread. Atualmente, o PHP 4 tem suporte para ISAPI, WSAPI, e NSAPI (no Windows), todos permitindo PHP ser usado como um plug-in em servidores multithreaded como Netscape FastTrack (iPlanet), Internet Information Server (IIS) da Microsoft, e O'Reilly's WebSite Pro. O comportamento é essencialmente o mesmo do modelo multiprocessado descrito anteriormente.

Se conexões persistentes não tem nenhuma funcionalidade a mais, para que elas servem?

A resposta é extremamente simples -- eficiência. Conexões persistentes são boas se a sobrecarga (overhead) para criar uma conexão ao seu servidor SQL for alta. Se essa sobrecarga é alta ou não depende de vários fatores. Como, qual tipo de banco de dados é, se está ou não na mesma máquina onde o servidor web está, o quão carregada a máquina onde está o servidor SQL está e assim por diante. O ponto é que se a sobrecarga de conexão for alta, conexões persistentes ajudam consideravelmente. Elas fazem com que os processos filhos simplesmente se conectem uma vez só durante toda sua duração, ao invés de cada vez que eles processam uma página que requer uma conexão ao servidor SQL. Isso significa que cada filho que abriu uma conexão persistente terá sua própria conexão persistente para o servidor. Por exemplo, se você tivesse 20 processos filhos diferentes que rodassem um script que fizesse uma conexão persistente à um servidor SQL, você teria 20 conexões diferentes servidor SQL, uma para cada filho.

Perceba, no entanto, que isso pode ter algumas desvantagens se você estiver usando um banco de dados com limite de conexões que são excedidas pela conexões persistentes dos filhos. Se o seu banco de dados tem um limite de 16 conexões simultâneas, e durante um momento de pico de acessos, 17 processos filhos tentarem se conectar, um deles não será capaz. Se houver bugs no seus scripts que não permitem que as conexões se fechem (como loops infinitos) o banco de dados com apenas 16 conexões pode rapidamente ficar sobrecarregado. Procure na documentação do seu banco de dados por informações sobre como lidar com conexões ociosas ou abandonadas.

Aviso

Existem mais alguns cuidados a se tomar quando usando conexões persistentes. Um deles é que, quando usando travamento de tabela em uma conexão persistente, se o script por qualquer razão não puder destravar a mesma, então scripts subsequentes usando a mesma conexão serão bloqueados indefinidamente e podem exigir que você ou reinicie o servidor httpd ou o servidor de banco de dados. Outro cuidado, é que quando usando transações, um bloco de transação também será carregado para o próximo script que usa aquela conexão se a execução do script terminar antes que o bloco de transação termine. Em ambos os casos, você pode usar register_shutdown_function() para registrar uma função simples de limpeza para destravar suas tabelas ou reverter suas transações. Melhor ainda, evite o problema completamente não utilizando conexões persistentes em scripts que usam travamento de tabelas ou transações (você ainda pode usar eles em outros casos).

Um resumo importante. Conexões persistente foram feitas para ter um mapeamento de um-para-um com conexões normais. Isso significa que você deve sempre ser capaz de substituir conexões persistentes com conexões não-persistentes e isso não mudará a maneira como seu script se comporta. Isso pode (e provavelmente irá) mudar a eficiência do seu script, mas não o seu comportamento!

Veja também 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().