PHP e PostgreSQL Um é pouco, dois é bom, três é demais Fabrízio de Royes Mello @fabriziomello
Fabrízio de Royes Mello • Empreendedor • Colaborador PostgreSQL
Não sou um programador PHP… já tentei um dia mas...
Contextualizando
$ git clone > git@github.com:fabriziomello/phpconference.git $ cd phpconference $ vagrant up $ vagrant ssh $ cd /mnt/bootstrap/php
<?php // Connection string $DSN = "host=localhost port=5432 user=phpconference dbname=phpconference password=phpconference"; ?>
Async Connection Aguarde conexão executando sua lógica
<?php // Try to connect to database phpconference $dbconn = pg_connect($DSN, PGSQL_CONNECT_ASYNC); // Wait for connection ... while( pg_connect_poll($dbconn) <> PGSQL_POLLING_OK ) { echo "Waiting for connection ...n"; usleep(100000); } echo "Connected ...n"; ?>
Async Query Execute sua lógica enquanto aguarda SQL
<?php $dbconn = pg_connect($DSN); $query = "WITH rnd AS (SELECT random()*5 AS n) SELECT pg_sleep(n), n, 'Some string' FROM rnd"; $secs = 0; if( !pg_connection_busy($dbconn) ) { $sent = pg_send_query($dbconn, $query); while( pg_connection_busy($dbconn) ) { $secs++; echo "Waiting $secs seconds ...n"; sleep(1); } $result = pg_get_result($dbconn); var_dump(pg_fetch_row($result)); ?>
LISTEN / NOTIFY Notificações Assíncronas com PostgreSQL
<?php $dbconn = pg_connect($DSN); pg_query($conn, 'LISTEN chat_room_1;'); while(1) { $notify = pg_get_notify($conn); if (!$notify) { echo "No messagesn"; } else { print_r($notify); } sleep(1); } ?>
Bulk Load Inserir dados em blocos no banco de dados
<?php $dbconn = pg_connect($DSN); pg_query($dbconn, "CREATE TABLE bar (a INT4, b CHAR(16), d NUMERIC)"); pg_query($dbconn, "COPY bar FROM stdin"); pg_put_line($dbconn, "3thello worldt4.5n"); pg_put_line($dbconn, "4tgoodbye worldt7.11n"); pg_put_line($dbconn, ".n"); pg_end_copy($dbconn); ?>
Dica “Unlogged Tables” • tipo especial de tabela que não gera Logs de Transação • tornam operações de escrita muito performática • não são “crash-safe” • não replicam pois não geram Logs de Transação • se combinado com COPY em alguns cenários pode ser de 10x a 100x mais (ou mais) rápido que INSERT em tabela regular
Cursores Lendo blocos de registros do banco
<?php $dbconn = pg_connect($DSN); pg_query($dbconn, 'START TRANSACTION;'); pg_query($dbconn, "DECLARE c CURSOR FOR SELECT i, 'Line '||i FROM generate_series(1,100) AS i"); while(pg_num_rows($result = pg_query($dbconn, 'FETCH 10 FROM c')) > 0) { while( $result = pg_fetch_row($result) ) { echo "Row: $row[0], $row[1]n"; } readline('<enter>'); } pg_query($dbconn, 'CLOSE c;'); pg_query($dbconn, 'COMMIT TRANSACTION;'); ?>
Prepared Statements Preparando execução de queries no banco
<?php $dbconn = pg_connect($DSN); pg_prepare($dbconn, 'insert_bar', 'INSERT INTO bar(a, b, d) VALUES ($1, $2, $3);'); for($i=1; $i<=10; $i++) { echo "Inserting item $i into 'bar' tablen"; pg_execute($dbconn, 'insert_bar', array($i, "Item $i", $i*2)); } ?>
Async Prepared Statements ● pg_send_prepare ● pg_send_execute
Ferramentas Algumas ferramentas de apoio
Debug através dos Logs log_line_prefix = '%t [%p]: [%l-1] db=%d,user=%u,app=%a,client=%h ' log_lock_waits = on log_min_duration_statement = 0 log_connections = on log_disconnections = on http://www.savepoint.blog.br/2015/01/20/trabalhando-com-logs-no-postgresql/
pgBadger ● ferramenta análise de logs ● descobrir queries lentas/frequentes ● bloqueios (locks) ● estatísticas de acessos e execução de queries ● estatísticas sobre vacuum/analyze ● uso de arquivos temporários ● sessões, checkpoints, ...
pgbouncer ● pool de conexões ○ session, transaction, statement ● uma espécie de “database proxy” ● dica: use com haproxy para criar um cluster “read-only” com distribuição de carga
pREST ● Transforma seu PostgreSQL em uma API REST ● Mantém um pool interno de conexões ● Além de operações CRUD sobre uma relação ○ junções ○ execução de scripts SQL armazenados servidor https://postgres.rest
contato@timbira.com.br

PHP e PostgreSQL: Um é pouco, dois é bom, três é demais

  • 1.
    PHP e PostgreSQL Umé pouco, dois é bom, três é demais Fabrízio de Royes Mello @fabriziomello
  • 2.
    Fabrízio de RoyesMello • Empreendedor • Colaborador PostgreSQL
  • 5.
    Não sou umprogramador PHP… já tentei um dia mas...
  • 6.
  • 7.
    $ git clone > git@github.com:fabriziomello/phpconference.git $ cd phpconference $ vagrant up $ vagrant ssh $ cd /mnt/bootstrap/php
  • 8.
    <?php // Connection string $DSN= "host=localhost port=5432 user=phpconference dbname=phpconference password=phpconference"; ?>
  • 9.
    Async Connection Aguarde conexãoexecutando sua lógica
  • 10.
    <?php // Try toconnect to database phpconference $dbconn = pg_connect($DSN, PGSQL_CONNECT_ASYNC); // Wait for connection ... while( pg_connect_poll($dbconn) <> PGSQL_POLLING_OK ) { echo "Waiting for connection ...n"; usleep(100000); } echo "Connected ...n"; ?>
  • 11.
    Async Query Execute sualógica enquanto aguarda SQL
  • 12.
    <?php $dbconn = pg_connect($DSN); $query= "WITH rnd AS (SELECT random()*5 AS n) SELECT pg_sleep(n), n, 'Some string' FROM rnd"; $secs = 0; if( !pg_connection_busy($dbconn) ) { $sent = pg_send_query($dbconn, $query); while( pg_connection_busy($dbconn) ) { $secs++; echo "Waiting $secs seconds ...n"; sleep(1); } $result = pg_get_result($dbconn); var_dump(pg_fetch_row($result)); ?>
  • 13.
    LISTEN / NOTIFY NotificaçõesAssíncronas com PostgreSQL
  • 14.
    <?php $dbconn = pg_connect($DSN); pg_query($conn,'LISTEN chat_room_1;'); while(1) { $notify = pg_get_notify($conn); if (!$notify) { echo "No messagesn"; } else { print_r($notify); } sleep(1); } ?>
  • 15.
    Bulk Load Inserir dadosem blocos no banco de dados
  • 16.
    <?php $dbconn = pg_connect($DSN); pg_query($dbconn,"CREATE TABLE bar (a INT4, b CHAR(16), d NUMERIC)"); pg_query($dbconn, "COPY bar FROM stdin"); pg_put_line($dbconn, "3thello worldt4.5n"); pg_put_line($dbconn, "4tgoodbye worldt7.11n"); pg_put_line($dbconn, ".n"); pg_end_copy($dbconn); ?>
  • 17.
    Dica “Unlogged Tables” •tipo especial de tabela que não gera Logs de Transação • tornam operações de escrita muito performática • não são “crash-safe” • não replicam pois não geram Logs de Transação • se combinado com COPY em alguns cenários pode ser de 10x a 100x mais (ou mais) rápido que INSERT em tabela regular
  • 18.
    Cursores Lendo blocos deregistros do banco
  • 19.
    <?php $dbconn = pg_connect($DSN); pg_query($dbconn,'START TRANSACTION;'); pg_query($dbconn, "DECLARE c CURSOR FOR SELECT i, 'Line '||i FROM generate_series(1,100) AS i"); while(pg_num_rows($result = pg_query($dbconn, 'FETCH 10 FROM c')) > 0) { while( $result = pg_fetch_row($result) ) { echo "Row: $row[0], $row[1]n"; } readline('<enter>'); } pg_query($dbconn, 'CLOSE c;'); pg_query($dbconn, 'COMMIT TRANSACTION;'); ?>
  • 20.
  • 21.
    <?php $dbconn = pg_connect($DSN); pg_prepare($dbconn,'insert_bar', 'INSERT INTO bar(a, b, d) VALUES ($1, $2, $3);'); for($i=1; $i<=10; $i++) { echo "Inserting item $i into 'bar' tablen"; pg_execute($dbconn, 'insert_bar', array($i, "Item $i", $i*2)); } ?>
  • 22.
    Async Prepared Statements ●pg_send_prepare ● pg_send_execute
  • 23.
  • 24.
    Debug através dosLogs log_line_prefix = '%t [%p]: [%l-1] db=%d,user=%u,app=%a,client=%h ' log_lock_waits = on log_min_duration_statement = 0 log_connections = on log_disconnections = on http://www.savepoint.blog.br/2015/01/20/trabalhando-com-logs-no-postgresql/
  • 25.
    pgBadger ● ferramenta análisede logs ● descobrir queries lentas/frequentes ● bloqueios (locks) ● estatísticas de acessos e execução de queries ● estatísticas sobre vacuum/analyze ● uso de arquivos temporários ● sessões, checkpoints, ...
  • 26.
    pgbouncer ● pool deconexões ○ session, transaction, statement ● uma espécie de “database proxy” ● dica: use com haproxy para criar um cluster “read-only” com distribuição de carga
  • 27.
    pREST ● Transforma seuPostgreSQL em uma API REST ● Mantém um pool interno de conexões ● Além de operações CRUD sobre uma relação ○ junções ○ execução de scripts SQL armazenados servidor https://postgres.rest
  • 30.