habilidade de gerar processos filhos (fork) para processamento em paralelo, e para isso usei uma classe para realizar esse trabalho. Confesso que no inicio tive um certo receio em implementar essa rotina em PHP, inclusive cogitei a possibilidade de faze-la em Perl, Python ou Ruby, mas como eu domino mais esta do que as outras e o tempo era curto implementei nela mesmo, e os resultados foram muito satisfatorios.COPY no lugar de INSERTA primeira coisa que fiz para continuar esse projeto foi *abolir* o INSERT... isso mesmo... nao tem INSERT... vc deve estar pensando que estou maluco e se perguntando: "Ta e como adicionar linhas a uma tabela entao?" R: usando COPY, ao inves de INSERT... na realidade implementei uma classe que armazena uma colecao (linhas) em memoria, e quando eu preciso uso um metodo para persistir os dados em uma tabela usando COPY... simples assim... entao o codigo usado para INSERT e algo do tipo:DDL da tabela exemplo:create table foo ( bar integer);PHP:$tabela = new PgCopy('foo');for ($i=0; $i<10; $i++) { $tabela->bar = $i; $tabela->insertValue(); // adiciona em memoria}$tabela->persist(); // realiza COPY dos dados em memoriaDividir para conquistarUm dos problemas que tinhamos com o processo antigo era justamente que ele era linear, ou seja, um processo apenas com inicio, meio e fim. Entao resolvi investir em programacao paralela, dividindo o grande volume de registros a processar em varios trabalhos menores sendo capaz de executar alguns em paralelo, de acordo com o nro de nucleos do servidor.Para tal atividades crio uma tabela que planeja a execucao do trabalho, ou seja, cria lotes para que o script possa processar em paralelo, isso baseado em uma chave artifical (sequencial) que existe no modelo e facilitou a criacao de trabalhos com lotes de N registros (neste caso usei 1000).A tabela que crio para planejar a execucao do ETL e algo do tipo:create table jobs ( id_start bigint, id_end bigint, status varchar, constraint jobs_pk primary key (id_start, id_end), constraint jobs_status_ck check (status in ('NOT RUNNING', 'RUNNING', 'FINISHED')));Dessa forma utilizo o "id_start" e "id_end" para buscar as informacoes na origem em "lotes" de 1000 (mil) registros, e com isso consigo disparar varios processos em paralelo, e dessa forma conseguimos aproveitar melhor os recursos do servidor e assim agilizar bastante o processo.Unlogged Tables sao bem legaisEsse novo recurso presente apartir da versao 9.1 permite criar tabelas que nao sao escritas no log de transacoes (WAL), acelerando e muito a insercao de registros na mesma.Assim cada processo disparado pelo script gera e escreve em uma unlogged table os dados, e junto com os processos de trabalho (workers) implementei um processo especial que serve com um tipo de coletor de lixo (garbage collector) para ir gradativamente lendo os lotes processados (unlogged tables geradas) e inserindo (com copy claro) na particao de destino.Com essa estrategia posso ter um certo nivel de escala na escrita pois consigo separar as tabelas em tablespaces distintas. Claro que se algum imprevisto ocorrer, tipo um desligamento nao previsto do servidor, o proprio script tem habilidade de detectar essa situacao e fazer uma limpeza geral antes de inicar