|
|||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||
|
Esta edição contém diversos artigos interessantes como contribuição de algumas pessoas muito prestativas. Devido à (felizes) obrigações familiares, meu próprio tempo na semana passada foi muito limitado. Acho que terei este mesmo dilema para a edição de 14 de Julho, porque planejo estar assistindo a (e discursando na) Conferência sobre Open Source da editora O'Reilly na semana anterior à esta edição. Sugestões sobre conteúdo são sempre bem vindas, mas são especialmente bem vindas para esta edição. Sugestões para esta edição serão válidas se enviadas até 4 de Julho. Muito obrigada especialmente para Sean Chittenden, Rao Kumar e ao Grupo de Usuários do PostgreSQL de São Francisco, e à você por sua paciência.
Para avaliar o limite de chamadas de funções em plpgsql e C, Sean Chittenden escreveu as funções abaixo. As funções rodaram em um laptop PIII de 600MHz. Em todas as vezes há uma média de 50 chamadas para uma função e o tempo decorrido é mostrado pelo EXPLAIN ANALYZE. A primeira função compara uma função em plpgsql e outra em C compatível. /* código pl/pgsql INÍCIO */ CREATE OR REPLACE FUNCTION t1() RETURNS INT AS ' DECLARE v_i INT; BEGIN v_i := 1; RETURN v_i; END; ' LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION t2() RETURNS INT AS ' DECLARE v_i INT; BEGIN SELECT 1 INTO v_i; RETURN v_i; END; ' LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION t3() RETURNS INT AS '/tmp/t3.so' LANGUAGE C; /* Fim */ Onde t3() é definido como: /* Início */ #include "executor/spi.h" int t3(void); int t3(void) { int v_i; v_i = 1; return(v_i); } /* Fim */ Estes testes são intencionalmente bem básicos. Eles todos poderiam somente retornar 1. Mas a tarefa é o que conta, mesmo que embora a versão em C seja otimizada para somente retornar(1). Esta é a vantagem de possuir um compilador real trabalhando para você. Para o primeiro teste de chamada, uma nova conexão é iniciada para todas interações. Carregar antecipadamente não faz qualquer diferença entre, se as bibliotecas foram carregadas ou não. Neste conjunto de resultados, a Primeira chamada(1) está com plpgsql.so carregado antecipadamente. A Primeira chamada(2) não tem o plpgsql.so carregado antecipadamente (novo recurso em pre-7.4). Função | Primeira | Primeira | Chamadas | chamada(1) | chamada(2) | Subsequentes -----------+-----------------+-----------------+------------------- t1() | 2.35msec | 3.34msec | 0.24msec t2() | 2.46msec | 3.45msec | 0.28msec t3() | 0.37msec | 0.75msec | 0.16msec Estes resultados não são o que interessa, mas nos mostra qual é o limite para chamadas de função em várias circunstâncias. Aqui está um conjunto de testes muito mais interessantes, no entanto, com t(4..6): CREATE OR REPLACE FUNCTION t4() RETURNS INT AS ' DECLARE v_i INT; ret INT; BEGIN FOR v_i IN 1..1000 LOOP ret := v_i; END LOOP; RETURN ret; END; ' LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION t5() RETURNS INT AS ' DECLARE v_i INT; ret INT; BEGIN FOR v_i IN 1..1000 LOOP SELECT v_i INTO ret; END LOOP; RETURN ret; END; ' LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION t6() RETURNS INT AS '/tmp/t6.so' LANGUAGE C; /* Início C/t6() */ #include "executor/spi.h" int t6(void); int t6(void) { int v_i; int ret; for (v_i = 0; v_i < 1000; v_i++) ret = v_i; return(ret); } /* Fim C */ Aqui a diferença começa a aparecer. t5() usa SELECT INTO ao invés de :=. Toda vez que um SELECT INTO é utilizado, ele tem que dizer para o backend (processo em segundo plano) para configurar um plano de consulta, embora no plpgsql, os planos estejam em cache. Nada chega perto de C... não é surpresa conseguir 1.000 interações extras. Função | Primeira | Primeira | Chamadas | chamada(1) | chamada(2) | Subsequentes -----------+-----------------+-----------------+------------------- t4() | 6.16msec | 9.17msec | 3.54msec t5() | 34.52msec | 41.18msec | 29.19msec t6() | 0.37msec | 0.77msec | 0.16msec O exemplo em C não executa consultas, mas isto não foi necessário para os testes apresentados. Percorrer registros está limitado pela E/S e o HD do laptop não tem a qualidade de um utilizado em servidor, então, funções matemáticas puras foram mais apropriadas para este nível de teste. O pl/pgsql tem o péssimo hábito de copiar dados com ROWTYPEs/RECORDs, uma vez que em C você pode usar um buffer de tamanho fixo e somente realloc()[ar] o espaço.
Em anexo está um utilitário para listar e terminar sessões do PostgreSQL. Este script irá funcionar com versões 7.2 ou superior. Este script usa kill -TERM, e não kill -9 para terminar as sessões. Script: pgsession pgsession : Lista/Termina sessões de usuários no banco de dados Sintaxe: pgsession [OPÇÃO]... [USUÁRIO] Opções: --h (help) mostra estas informações de ajuda, e sai -l (list) lista as sessões do banco de dados -k (kill) termina (aborta) uma sessões do banco de dados -f (force) força terminar uma sessão (não pede confirmação, utilize em conjunto com a opção -k) -u USUÁRIO especifica o nome do usuário do banco de dados -p PID especifica o número do processo do usuário (pid) Exemplos: pgsession -l lista todas as sessões pgsession -l -u <user> lista as sessões do usuário pgsession -k termina todas as sessões pgsession -k -f força terminar todas as sessões pgsession -k -u <user> terminar as sessões do usuário pgsession -k -p <pid> termina a sessão com um PID específicoVocê pode baixar o script do pgsession na página do Tidbits. Observação: uma lista das sessões e suas respectivas consultas está disponível também em psql utilizando: select * from pg_stat_activity;
Se na sua máquina, a função getpagesize() retorna 4096, isto significa que o tamanho da página para o postgresql é de 4096 bytes? A documentação para "Monitoring disk usage" (monitorando o uso do disco) diz que o tamanho da página do postgres é "geralmente" de 8KB (8192 bytes). Qual dos dois é o correto? O tamanho da página do postgreSQL é determinado em tempo de compilação e, dado que a maioria das pessoas não mexem nisso, continuará sendo 8KB em 99.9% dos casos.
A consulta a seguir resultou em uma mensagem "Cancelled Execution" (execução cancelada) quando utilizada com ODBC no windows e quando a lista continha várias centenas de itens. select field1 from table where field2 in (lista); O problema parece ser unicamente no driver ODBC. A consulta executa corretamente pelo psql e também funciona corretamente para muitas listas mais curtas. Duas maneiras de contornar este problema foram sugeridas. A primeira sugestão cria uma instrução equivalente utilizando LIKE. SELECT field1 FROM table WHERE field2 IN (1,2,3,4,5,6,7); SELECT field1 FROM table WHERE ',1,2,3,4,5,6,7,' like '%,'||field2||',%'; A segunda maneira de contornar este problema é provavelmente mais rápida em tempo de execução. A sugestão está em colocar a lista em uma tabela, provavelmente uma tabela temporária, e alterar a consulta para executar uma junção com a tabela. select field1 from table t, listtable l where t.field2 = l.list_item;
A palestra que estarei ministrando na OSCON será sobre Executar Funções de Conjunto no PostgreSQL em plpython. Este assunto foi tratado superficialmente na Edição #23. Na conferência, a palestra terá mais exemplos e cobrirá mais detalhes. Eu terei prazer em publicar os exemplos adicionais e o texto da palestra após a conferência. Uma curta descrição da palestra se encontra logo abaixo: Um questionamento constante e aparente em muitos forums é como executar funções no registro corrente baseado no registro anterior. Esta palestra mostrará uma técnica em detalhe. Esta técnica pode ser aplicada em diversas tarefas distintas provendo uma nova maneira de utilizar seus dados. |
||||||||||||||||||||||||||||||||||||
Comentários e Correções são bem vindos. Sugestões e contribuições de itens também são bem vindos. Envie-os!. Copyright A. Elein Mustain 2003 Traduzidos por Juliano da Silva Ignacio |