|
|||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||
|
There is another new link on PostgreSQL General Bits for Portugues speakers. In contains articles from General Bits translated by Juliano da Silva Ignacio. Welcome to Portugues readers. I'm sure you will enjoy Juliano's work. Há um novo link no General Bits do PostgreSQL para o idioma Português. Nele estão contidos artigos do General Bits traduzidos por Juliano da Silva Ignacio. Bem vindos leitores da Língua Portuguesa. Eu tenho certeza que o trabalho feito por Juliano irá agradá-los. Este edição é o primeiro de uma série PostgreSQL General Bits Edição: 26
Quando uma boa função em pl/pgsql é criada, tenha certeza de que as variáveis declaradas não tenham os mesmos nomes que os nomes de colunas ou tabelas utilizadas na função. Variáveis utilizadas em funções escritas em pl/pgsql terão precedência sobre o nome de colunas ou tabelas e, nem sempre é esta a intenção. O que deveria também ser notado, enquanto estamos neste assunto, é que também não se deve usar palavras chaves do SQL como nomes de variáveis, mas você já deve saber disso, não é mesmo? É particularmente importante revisar os nomes das variáveis atrás de conflitos se uma função em pl/pgsql não está se comportando como deveria se comportar. Um exemplo disto está na função abaixo, que tem a variável project_code declarada e depois, numa consulta dentro da função, retorna a coluna (com mesmo nome) project_code de uma tabela. CREATE FUNCTION UpdateNextProjectCode() RETURNS OPAQUE AS ' DECLARE project_code INTEGER; ... BEGIN ... OPEN used_project_codes FOR SELECT project_code FROM projects WHERE project_code > 0 ORDER BY project_code ASC; ...A variável project_code ainda não foi inicializada no pl/pgsql, portanto seu valor é NULL. As variáveis em pl/pgsql são expandidas (tem seu conteúdo utilizado) antes de uma consulta ser executada, então, a instrução abaixo foi, o que foi executado (oops): SELECT NULL FROM projects WHERE NULL > 0 ORDER BY NULL ASC;Isso provavelmente não era o que se pretendia originalmente. O problema de conflito de nomes no pl/pgsql é muito comum, portanto, adicione-o à sua lista de verificação quando estiver testando e 'debugando' funções no servidor.
O tamanho de uma tabela não tem muita importância com relação à performance quando se trata de um servidor bem configurado e com indexação coerente. Algumas dezenas, não, digo, centenas de milhares de registros é um tamanho perfeitamente razoável para uma tabela e muitos ainda irão achar que é pequena. Um questionamento sobre portar uma tabela de 95000 registros trouxe à tona os seguintes depoimentos e precauções: Eu tenho uma quantidade de 1.000.000 ou mais de registros por tabela (muito mais em alguns casos) rodando em máquinas simples de poucos recursos (Celerons com HDs IDE de 5400rpm, Netras) e performance perfeitamente adequada para o uso típico. -- Steve Quase ridiculamente pequeno :) Sim, aquelas buscas por índices sequenciais e tsearch poderão matar uma aplicação, mas as consultas de seleção irão voar. -- Nigel Você está absolutamente correto sobre haver muitos outros fatores que determinam a performance por parte da contagem de registros. Tendo dito isto, tenho tabelas com mais de um milhão de entradas em sistemas de uso contínuo que mostram um ótimo desempenho utilizando consultas e índices, e também muito aceitável em consultas que requerem uma busca seqüencial. -- Ryan Se as consultas são de seleção e tipicamente indexadas, ou você tem possui RAM suficiente, ou - como então eu diria - não haveria muita diferença entre dividir tabelas ou combiná-las em apenas uma. Nós utilizamos o PostgreSQL para muitas coisas que possuem mais do que 90.000 registros. Nós temos uma tabela que usamos para juntar arquivos log de múltiplos servidores e então classificá-los cronologicamente.
Especialmente em consultas lentas, isto ajuda na capacidade de armazenar o conjunto de dados resultante e reusá-lo novamente (se necessário). Isto pode ser um pouco complicado se sua aplicação é uma aplicação para internet. Neste caso, é importante saber o escopo no qual voce quer manter seu conjunto de resultados. Por transação? Por conexão? Por sessão? O meio "usual" para guardar em cache o resultado de consultas é utilizando CURSORes: BEGIN; DECLARE cursorname FOR query; FETCH number_of_rows FROM cursorname; MOVE {FORWARD|BACKWARD} number_of_rows IN cursorname; ... COMMIT;Este método tem um problema quando se trabalha através de transações e conexões. Usando conexões conjuntas persistentes (persistant pooled connections) às vezes parece ser uma boa opção, mas às vezes o benefício da performance não vale o esforço despendido. Scott Marlow escreve, "Conexões persistentes são, geralmente 1000 vezes (ou mais) mais rápido do que estabelecer conexões não-persistentes, mas quando conexões não-persistentes conectam em apenas uma fração de segundo (1/10.000), não representa um grande ganho de velocidade possuir conexões persistentes."Utilizando conexões persistentes é de boa prática confirmar (COMMIT) ou desfazer (ROLLBACK) uma transação antes de liberar a conexão do poll (conjunto) porque é difícil manter uma transação através de conexões conjuntas (pooled connections). O acompanhamento (tracking) da sessão é necessário, assim como, a coordenação de todas as sessões com suas respectivas conexões. Muitos utilitários de conexão conjunta (connection pooling) não se conformam com estes requerimentos. Exige-se que os cursores estejam dentro de uma transação, dessa maneira seus benefícios estão limitados pelo escopo da mesma. Isto cuida da rejeição de conexões conjuntas (connection pools) com cursores, como uma solução para quando você quiser um cursor para a última sessão. A outra maneira "usual" é guardar em cache os dados de uma aplicação cliente em estruturas que estejam disponíveis. Isto é muito comum, ainda que o benefício da disponibilidade, armazenamento e manipulação devam ser comparados ao custo de executar novamente a consulta. Uma tabela temporaria para armazenar a informação consultada não funcionará porque irá desaparecer quando a conexão for fechada. Manipulando cuidadosamente os cursores podem funcionar com conexões conjuntas (connection pooling). A alternativa é uma simples tabela de resultados. Algumas considerações teriam que ser feitas para coletar o lixo da "simples" tabela temporaria, dependendo do escopo desejado do conjunto de dados.
A sintaxe para DISTINCT é facilmente mal interpretada. Aqui está uma definição normal: SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expression [ AS output_name ] [, ...] Isto é fácil de escrever: SELECT DISTINCT ON (dai_genres.id), dsc FROM dai_genresquando você realmente sabe o que significa SELECT DISTINCT ON (dai_genres.id) dsc FROM dai_genresTire fora a vírgula após o parêntesis. A cláusula DISTINCT está antes e separada da lista de destino (colunas de resultado). A coluna usada na cláusula DISTINCT não está inclusa na lista de destino a menos que você a inclua especificamente pelo nome ou implicitamente a inclua com um *. SELECT DISTINCT ON (dai_genres.id) * FROM dai_genres Foi discutido se a sintaxe deveria ter tido colchetes em volta da lista de destino. Isto foi sugerido para separar as cláusulas opcionais DISTINCT ou ALL da lista de destino. Mas, não estou convencido; e novamente ninguém me questionou :-) Foi também colocado de fora a parte do OR (operador alternativo) na lista de destino: * | expression [ AS output_name ] [, ...]que apontava que você não poderia fazer SELECT *, oid FROM ...
o qual todos nós sabemos, é uma lista de destino válida.
Isto é o que o SQL Spec diz sobre os simbolos: 3.2 NotaçãoNós nos importamos muito com a sintaxe como uma ponte entre o nosso entendimento e o entendimento do computador. Discussões sobre particularidades da sintaxe ajudam-nos a criar uma maneira fácil e legível de entender o modo de expressar as instruções.[ ] Colchetes indicam elementos opcionais na fórmula. A parte da fórmula contida nos colchetes deve ser explicitamente especificada ou deve ser omitida.{ } Chaves agrupam os elementos na fórmula. A parte da fórmula contida nas chaves deve ser explicitamente especificada.| O operador alternativo. A barra vertical indica que a parte da fórmula seguinte à barra é uma alternativa para a parte que precede a mesma barra. Se a barra vertical aparece numa posição onde não está contida em chaves ou colchetes, ela especifica uma alternativa completa para um elemento definido pela regra de produção. Se a barra vertical aparece entre chaves ou colchetes, isto especifica alternativas para o conteúdo do mais interno par de chaves ou colchetes.
Uma dúvida sobre como percorrer (loop) um vetor (array) trouxe um belo exemplo de como fazer isso exatamente (por Joe Conway). Este exemplo necessita a versão 7.3. Para funções similares, veja também Ediçao 24 Artigo 6 .
CREATE OR REPLACE FUNCTION atest(INT[]) RETURNS TEXT AS ' DECLARE mya alias for $1; myret text = ''''; low int; high int; BEGIN low := replace(split_part(array_dims(mya),'':'',1),''['','''')::int; high := replace(split_part(array_dims(mya),'':'',2),'']'','''')::int; FOR i IN low..high LOOP myret := myret || ''|'' || mya[i]; END LOOP; RETURN myret; END; ' LANGUAGE 'plpgsql' IMMUTABLE STRICT; regression=# select atest('{1,2,3,4}'::int[]); atest ---------- |1|2|3|4 (1 row)
|
||||||||||||||||||||||||||||||||||||
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 |