Problemas no inner join com subselect no PostgreSQL


O PostgreSQL sempre tenta elevar um "join" com um "subselect " em um "join" simples. Assim, uma consulta do tipo:

SELECT * FROM tabela1 INNER JOIN (
SELECT * FROM tabela2 WHERE tabela2.saldo=1000
) ON tabela1.divida_id = tabela2.divida_id;

É elevada a um INNER JOIN simples assim:

SELECT * FROM tabela1 INNER JOIN tabela2 ON tabela1.divida_id = tabela2.divida_id;

Isso pode ser um problema quando a tabela onde o subselect é executado é muito grande!

Para "forçar" a execução do subselect podemos utilizar um agregador (limit, order by, etc ..) como no exemplo abaixo:

SELECT * FROM tabela1 INNER JOIN (
SELECT * FROM tabela2 WHERE tabela2.saldo=1000 ORDER BY tabeal2.divida_id
) ON tabela1.divida_id = tabela2.divida_id;

Perl: Memory flush (desativando o buffer) ao gerar arquivos grandes


"Parsear" arquivos texto utilizando Perl é algo muito fácil, porém alguns problemas começam aparecer quando os arquivos são muito grandes.

Um deles é o acúmulo de cache na memória (buffer) durante a escrita de um arquivo muito grande. Por padrão a Perl escreve no buffer antes de escrever o arquivo em disco. Para "forçar" a escrita direta no disco (autoflush da memória) utilize select() e a variável especial $| para controlar o autoflushing (veja perlvar/$ e perlfunc):

$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);

Ou, para ficar mais legível podemos utilizar o módulo IO:Handle:

use IO::Handle;
open(OUT, ">out.txt");
OUT->autoflush(1);

Reduzindo imagens via shell no Linux


Apenas uma dica rápida para reduzir todas as imagens de um diretório via shell usando o comando convert do linux:

Dentro do diretório com a fotos crie um diretório chamado reduzidas:

mkdir reduzidas

Depois execute o comando abaixo, onde 1024 é a largura em pixel da nova image

for i in *.jpg; do convert -resize 1024 "$i" reduzidas/"$i"; done

Espere e todas as fotos com o novo tamanho estarão no diretório reduzidas

DBD::mysql por padrão carrega todo o resultado das consultas SQL na memória

Eu estava com problemas de memória ao fazer uma simples consulta SQL via Perl utilizando o módulo DBI com o Mysql. Como eu sabia que a quantidade de registros retornados eram muitos (mais de 100 milhões), acabei utilizando o método fetchrow_array e escrevia a saída direto em um arquivo texto (melhor perder espaço em disco do que acabar com a memória do servidor, rs...).

Apesar da minha precaução, o script Perl consumia toda a memória no servidor. Pesquisando um pouco descobri que o driver DBD::mysql utilizando pelo DBI, por padrão, carrega todos os dados na memória ao chamarmos o método $sth->execute (mysql_store_result). Para evitar isso, devemos habilitar o método mysql_use_result, que lê os dados um a um do banco de dados ao utilizarmos o método fetchrow_array :

my $sth = $dbh->prepare($sql);
$sth->{"mysql_use_result"} = 1;
$sth->execute;

Com isso, meu script não consumia nem 1% da memória do servidor.

OBS: Não esqueça de utilizar o método $sth->finnish antes de fazer outra requisição ao banco de dados.