COPYmaintenance_work_memmax_wal_sizeANALYZE depoisPode ser necessário inserir uma grande quantidade de dados ao carregar o banco de dados pela primeira vez. Esta seção contém algumas sugestões sobre como tornar este processo o mais eficiente possível. [105]
Quando são usados vários comandos INSERT, é melhor
desativar o AUTOCOMMIT (efetivação automática),
e fazer o COMMIT apenas no final.
(Em puro SQL, isto significa executar o comando
BEGIN no início e o comando
COMMIT no final da transação.
Algumas bibliotecas cliente podem fazer isto sem que seja visto;
neste caso, é necessário garantir que a biblioteca possa fazer isto
quando quiser.)
Se for permitido que cada inserção seja efetivada em separado,
o PostgreSQL fará muito trabalho para
cada linha adicionada.
Um benefício adicional de fazer todas as inserções em uma única
transação é que, se a inserção de uma linha falhar, a inserção de
todas as linhas inseridas até este ponto será desfeita, para que
não se fique preso a dados parcialmente carregados.
COPY #
Deve ser usado o COPY
para carregar todas as linhas em um único comando, em vez de usar
uma série de comandos INSERT.
O comando COPY é otimizado para carregar um
grande número de linhas; embora seja menos flexível do que o comando
INSERT, produz uma sobrecarga muito
menor para grandes cargas de dados.
Como COPY é um comando único, não há necessidade
de desativar o AUTOCOMMIT se for usado este
comando para carregar a tabela.
Se não for possível usar o comando COPY,
pode ser benéfico usar
PREPARE
para criar uma instrução INSERT preparada e,
em seguida, usar EXECUTE quantas vezes
forem necessárias.
Isto evita parte da sobrecarga de analisar e planejar repetidamente
o comando INSERT.
Diferentes interfaces fornecem esta facilidade de maneiras diferentes;
procure por “instruções preparadas” na documentação
da interface.
Note que carregar um grande número de linhas usando o comando
COPY é quase sempre mais rápido do que usar
o comando INSERT, mesmo se for usado
PREPARE, e várias inserções forem agrupadas
em uma única transação.
O comando COPY é mais rápido quando usado na
mesma transação que um comando anterior CREATE TABLE
ou TRUNCATE.
Nestes casos, nada precisa ser escrito no WAL,
porque em caso de erro, os arquivos contendo os dados recém-carregados
serão removidos de qualquer maneira.
Entretanto, esta consideração só se aplica quando a variável de
configuração wal_level for
minimal, caso contrário todos os comandos
devem escrever no WAL.
Se estivermos carregando uma tabela recém-criada, o método mais
rápido é criar a tabela, carregar em massa os dados da tabela usando
COPY, e criar os índices necessários para a tabela.
Criar um índice em dados pré-existentes é mais rápido do que
atualizá-lo incrementalmente à medida que cada linha é carregada.
Se estivermos adicionando uma grande quantidade de dados a uma tabela existente, pode ser um ganho eliminar os índices, carregar a tabela e, em seguida, recriar os índices. Obviamente, o desempenho do banco de dados para os demais usuários pode sofrer durante o tempo em que os índices estão ausentes. Deve-se pensar duas vezes antes de remover um índice exclusivo, porque a verificação de erros proporcionada pela restrição de unicidade estará perdida enquanto o índice estiver ausente.
Assim como nos índices, uma restrição de chave estrangeira pode ser verificada “em massa” com mais eficiência do que linha por linha. Portanto, pode ser útil eliminar as restrições de chave estrangeira, carregar os dados, e recriar as restrições. Novamente, deve haver um equilíbrio entre a velocidade de carga dos dados e a perda de verificação de erros enquanto a restrição estiver ausente.
Além disso, quando se carrega dados em uma tabela com restrições de chave estrangeira existentes, cada nova linha requer uma entrada na lista de eventos de gatilho pendentes do servidor (já que é o disparo de um gatilho que verifica a restrição de chave estrangeira da linha). Carregar muitos milhões de linhas pode fazer com que a fila de eventos de gatilho estoure a memória disponível, levando a um swap intolerável, ou até mesmo a uma falha total do comando. Portanto, pode ser necessário, e não apenas desejável, remover e reaplicar as chaves estrangeiras ao carregar uma grande quantidade de dados. Se a remoção temporária da restrição não for aceitável, o único outro recurso pode ser dividir a operação de carga em transações menores.
maintenance_work_mem #
O aumento temporário da variável de configuração
maintenance_work_mem, enquanto se carrega
uma grande quantidade de dados, pode melhorar o desempenho.
Isto ajuda a acelerar os comandos CREATE INDEX
e os comandos ALTER TABLE ADD FOREIGN KEY.
Este aumento não fará muito pelo comando COPY
em si, então este conselho só é útil quando se está usando uma
das técnicas acima, ou as duas.
max_wal_size #
O aumento temporário da variável de configuração
max_wal_size também pode tornar as grandes
cargas de dados mais rápidas.
Isto ocorre, porque carregar uma grande quantidade de dados
no PostgreSQL faz com que os pontos de
verificação ocorram com uma frequência acima da normal
(especificado pela variável de configuração
checkpoint_timeout).
Sempre que ocorre um ponto de verificação, todas as páginas sujas
devem ser descarregadas para o disco.
Ao aumentar a variável de configuração max_wal_size
temporariamente durante a carga de dados em massa, o número de
pontos de verificação necessários pode ser reduzido.
Ao carregar grandes quantidades de dados em uma instância que usa
arquivamento do WAL ou replicação por fluxo, pode ser mais rápido
fazer uma nova cópia de segurança base após a conclusão do
carregamento do que processar uma grande quantidade de dados
incrementais do WAL.
Para evitar o arquivamento incremental do WAL
durante o carregamento, deve ser desativado o arquivamento e a
replicação por fluxo definindo
wal_level como minimal,
archive_mode como off e
max_wal_senders como zero.
Observe, porém, que a alteração destas configurações exige a
reinicialização do servidor e torna qualquer cópia de segurança base
feita anteriormente inútil para recuperação de arquivamento e para
criação de um servidor secundário, o que pode levar à perda de dados.
Além de evitar o tempo para processar os dados do WAL
pelo arquivador ou remetente do WAL, esta
configuração torna certos comandos mais rápidos, porque não escrevem
no WAL se wal_level for igual
a minimal, e a subtransação corrente
(ou transação de nível superior) criou ou truncou a tabela ou
índice que estes comandos alteram.
(Pode ser garantida uma segurança contra falhas mais econômica
executando a função fsync no final, do que
escrevendo no WAL.)
ANALYZE depois #
Sempre que se altera muito a distribuição dos dados
de uma tabela, é altamente recomendável executar o comando
ANALYZE.
Isto inclui a carga em massa de uma grande quantidade de dados na tabela.
A execução do comando ANALYZE
(ou VACUUM ANALYZE) garante que o planejador
tenha estatísticas atualizadas sobre a tabela.
Sem estatísticas, ou com estatísticas obsoletas, o planejador pode
tomar decisões ruins durante o planejamento de consultas, levando
a um desempenho ruim em qualquer tabela com estatísticas imprecisas
ou inexistentes.
Note que se o processo autovacuum estiver
ativado, então poderá executar o comando ANALYZE
automaticamente; veja Atualização das estatísticas do planejador e a
Autovacuum para obter mais informações.
Os scripts de cópia de segurança gerados pela aplicação pg_dump aplicam automaticamente várias, mas não todas, as diretrizes acima. Para recuperar uma cópia de segurança feita pelo pg_dump o mais rápido possível, é necessário fazer algumas coisas extras manualmente. (Note que estes pontos se aplicam ao recuperar a cópia de segurança, e não ao criar a cópia de segurança. Os mesmos pontos se aplicam ao carregar uma cópia de segurança de texto usando o psql, ou usando o pg_restore para carregar um arquivo criado pelo pg_dump.)
Por padrão, a aplicação pg_dump
usa o comando COPY e, quando está gerando uma
cópia de segurança completa de esquema e dados, é cuidadoso ao
carregar os dados antes de criar os índices e chaves estrangeiras.
Portanto, neste caso, várias diretrizes são tratadas automaticamente.
O que resta a você fazer é:
Definir os valores apropriados (ou seja, maiores que o normal)
para maintenance_work_mem e
max_wal_size.
Se estiver sendo usado o arquivamento, ou replicação do
WAL por fluxo, considerar desativá-los
durante a recuperação.
Para fazer isto, deve ser definida a variável de configuração
archive_mode como off,
wal_level como minimal e
max_wal_senders igual a zero, antes de carregar
a cópia de segurança.
Depois, definidos de volta para os valores corretos, e criada uma
nova cópia de segurança do banco de dados.
Experimentar o modo paralelo de cópia de segurança e recuperação
das aplicações pg_dump e
pg_restore, e descobrir o número
ideal de trabalhos concorrentes a serem usados.
Realizar a cópia de segurança e recuperação em paralelo por meio
da opção -j deve fornecer um desempenho
muito melhor em comparação com o modo serial.
Considerar se toda a cópia de segurança deve ser recuperada como
uma única transação.
Para fazer isto, deve ser passada a opção de linha de comando
-1 ou --single-transaction para o
psql ou pg_restore.
Ao usar este modo, mesmo o menor dos erros desfaz toda a
recuperação, possivelmente descartando muitas horas de processamento.
Dependendo de como os dados estão inter-relacionados, isto pode
parecer preferível à limpeza manual, ou não.
Os comandos COPY executam mais rapidamente
quando é usada uma única transação, e o arquivamento do
WAL está desativado.
Se estiverem disponíveis vários processadores no servidor de banco de dados,
deve ser considerado o uso da opção --jobs do
pg_restore. Esta opção permite
carga de dados e criação de índices simultaneamente.
Executar o comando ANALYZE depois.
Uma cópia de segurança somente de dados ainda usa o comando
COPY, mas não exclui nem recria índices,
e normalmente não toca em chaves estrangeiras
[106].
Portanto, ao carregar uma cópia de segurança somente de dados,
cabe a você excluir e recriar índices e chaves estrangeiras se
desejar usar estas técnicas.
Ainda é útil aumentar a variável de configuração
max_wal_size enquanto carrega os dados,
mas não se preocupe em aumentar a variável de configuração
maintenance_work_mem;
em vez disso, você faria isto ao recriar manualmente índices
e chaves estrangeiras posteriormente.
E não se esqueça de executar o comando ANALYZE
quando terminar; veja Atualização das estatísticas do planejador e a
Autovacuum para obter mais informações.
[105] Veja também: IBM - Carregamento de dados em tabelas Db2 (N. T.)
[106]
Pode ser obtido o efeito de desativar as chaves estrangeiras
usando a opção --disable-triggers —
mas deve-se notar que isto elimina, em vez de apenas adiar,
a validação de chave estrangeira, portanto, é possível inserir
dados incorretos se esta opção for usada.