Como descubro até que ponto minha consulta no PostgreSQL está?


35

Eu tenho uma idéia bastante decente de quantas linhas minha consulta SELECT ... INTO realmente processará (por exemplo, eu sei quantas irão se materializar).

Entendo que o PostgreSQL não me diga se está completo, existe uma maneira (enterrada nos logs, tabelas de sistema ou de outra forma) que eu possa descobrir quantas linhas foram bombeadas para a tabela de destino ou que foram lidas pela consulta SELECT ?

Respostas:


33

Como Daniel Vérité mencionou, não parece haver uma solução genérica. Ao carregar dados em uma tabela a partir de um arquivo, a seguinte técnica pode ser usada para obter o progresso da carga.

Barra de progresso do console de comando COPY

Crie uma tabela vazia.

CREATE TABLE mytest (n int);

Crie um arquivo de dados com 10 milhões de linhas para carregar na tabela.

$ seq 10000000 > /tmp/data.txt

Carregue dados do arquivo na tabela e exiba uma barra de progresso.

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

Demo

insira a descrição da imagem aqui

Como isso funciona

Usando a opção STDIN dos comandos de cópia, podemos alimentar os dados para a operação de cópia de outro processo. O comando pv produzirá um arquivo e acompanhará seu progresso, exibindo uma barra de progresso, ETA, tempo total decorrido e a taxa de transferência de dados.

Barra de progresso gráfico do comando COPY

Usando a mesma técnica geral, podemos exibir uma barra de progresso em um aplicativo gráfico ou em um aplicativo baseado na Web. Usando python, por exemplo, o módulo psycopg2 permite chamar o comando copy com um objeto de arquivo de sua escolha. Você pode acompanhar o quanto do seu objeto de arquivo foi lido e exibir uma barra de progresso.


2
Eu nunca havia encontrado o pvcomando antes, e ele não estava instalado no meu servidor Debian por padrão, mas está no repositório. A descrição diz "pv (Pipe Viewer) pode ser inserido em qualquer pipeline normal entre dois processos para fornecer uma indicação visual da rapidez com que os dados estão passando". Um comando muito útil!
Richard Turner

27

Não parece haver um método genérico suportado, mas existem alguns truques que podem ser usados ​​em contextos limitados para avaliar o progresso de uma consulta individual. Aqui estão alguns deles.

Sequências

Quando uma consulta SELECT ou UPDATE inclui alguma nextval(sequence_name), ou um INSERT possui uma coluna de destino com um nextvalpadrão, o valor atual da sequência pode ser consultado repetidamente em outra sessão com SELECT sequence_name.last_value. Funciona porque as seqüências não são limitadas por transações. Quando o plano de execução é tal que a sequência é incrementada linearmente durante a consulta, ela pode ser usada como um indicador de progresso.

pgstattuple

O módulo contrg pgstattuple fornece funções que podem ser exibidas diretamente nas páginas de dados. Parece que quando as tuplas são inseridas em uma tabela vazia e ainda não confirmadas, elas são contadas no dead_tuple_countcampo a partir da pgstattuplefunção.

Demo com 9.1: crie uma tabela vazia

CREATE TABLE tt AS (n numeric);

Vamos inserir 10 milhões de linhas nele:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

Em outra sessão, verifique pgstattuple a cada segundo durante a inserção:

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

Resultados:

0 0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0 0

Ele volta a 0 quando a inserção é concluída (todas as tuplas se tornam visíveis e ativas).

Esse truque também pode ser usado quando a tabela não é criada recentemente, mas dead_tuple_counté provável que a inicial tenha um valor diferente de zero e também pode ser alterada simultaneamente se outra atividade de gravação, como o vácuo automático, estiver em andamento (presumivelmente? Não sabe ao certo qual nível de simultaneidade esperada com autovacuum).

No entanto, não pode ser usado se a tabela for criada pela própria instrução ( CREATE TABLE ... AS SELECTou SELECT * INTO newtable), pois a criação é transacionada. A solução alternativa seria criar a tabela sem linhas (adicionar LIMIT 0) e preenchê-la na próxima transação.

Observe que pgstattupleisso não é gratuito: ele varre a mesa inteira a cada chamada. Também é limitado a superusuários.

Contador personalizado

No blog de Pavel Stehule, ele fornece uma função de contador implementada em C que gera AVISOS em um número especificado de execuções. Você precisa combinar a função com a consulta de alguma forma para permitir que o executor a chame. Os avisos são enviados durante a consulta e eles não precisam de uma sessão separada, apenas um cliente SQL que os exibe ( psqlsendo o candidato óbvio).

Exemplo de INSERT INTO retrabalhado para gerar avisos:

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

Pergunta relacionada sobre stackoverflow, para funções:
Como relatar o progresso da função PostgreSQL de longa execução para o cliente

Opções futuras?

Em maio de 2017, existe um patch promissor enviado à comunidade de desenvolvedores: [PATCH v2] Comando Progress para monitorar a progressão de consultas SQL de longa execução

que pode acabar como uma solução genérica no PostgreSQL 11 ou posterior. Os usuários que desejam participar dos recursos de trabalho em andamento podem aplicar a versão mais recente do patch e tentar o PROGRESScomando proposto .


3

Até que a funcionalidade do relatório de progresso não seja estendida, como o @AmirAliAkbari mencionado em sua resposta, aqui está uma solução alternativa no nível do SO.

Isso funciona apenas em Linux, mas provavelmente existem soluções semelhantes facilmente acessíveis para qualquer sistema operacional.

A maior vantagem e também a desvantagem de PostgreSQL, que todos os seus infra- estruturas são simples processos de segmento único, utilizando lseek(), read()e write()para manipular os seus ficheiros de mesa, enquanto eles estão a interagir em MEM e fechaduras partilhada.

Como resultado, todos os seus processos de back-end estão funcionando sempre em uma única consulta, que pode ser facilmente encontrada e facilmente straced.

Primeiro, você pode ver o PID de back-end em SELECT * FROM pg_stat_activity;:

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

A terceira coluna é o pid. No PostgreSQL, é o mesmo que o processo Linux pid do back-end.

Em seguida, você pode rastreá-lo, por exemplo, por um strace -p 20019 -s 8192: ( -s 8192é útil porque o postgresql funciona com blocos de 8192 bytes).

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

Os significados:

  • sendtoacontece se o back-end responder algo a um cliente. No exemplo, ele responde ao resultado de uma INSERTconsulta.
  • recvfromacontece se o back-end recebe algo de um cliente. Geralmente, é uma nova consulta, no exemplo, outra INSERT.
  • lseek acontece se o back-end muda de posição em um arquivo de tabela.
  • read acontece se o back-end lê um bloco de um arquivo de tabela.
  • write acontece se o back-end grava um bloco em um arquivo de tabela.

No caso de reade write, você também pode ver o conteúdo desse bloco na tabela. Pode ajudar muito a entender, o que está fazendo e onde está.

No caso de recvfrom, você pode ver a consulta real do que o back-end possui.


2

Como dito em outras respostas, atualmente não há como direcionar os relatórios de progresso em geral.

O PostgreSQL tem a capacidade de relatar o progresso de certos comandos durante a execução do comando. Atualmente, o único comando que suporta relatórios de progresso é VACUUM. Isso pode ser expandido no futuro.

No entanto, a partir da 9.6, sempre que VACUUMestiver em execução, a pg_stat_progress_vacuumexibição conterá uma linha para cada back-end (incluindo processos de trabalho com vácuo automático) que está aspirando no momento. Detalhes adicionais pg_stat_progress_vacuumpodem ser encontrados na documentação: 27.4 Relatório de progresso .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.