EXPLAIN

EXPLAIN — mostra o plano de execução de uma instrução

Sinopse

EXPLAIN [ ( opção [, ...] ) ] instrução

onde opção pode ser uma entre:

    ANALYZE [ booleano ]
    VERBOSE [ booleano ]
    COSTS [ booleano ]
    SETTINGS [ booleano ]
    GENERIC_PLAN [ booleano ]
    BUFFERS [ booleano ]
    SERIALIZE [ { NONE | TEXT | BINARY } ]
    WAL [ booleano ]
    TIMING [ booleano ]
    SUMMARY [ booleano ]
    MEMORY [ booleano ]
    FORMAT { TEXT | XML | JSON | YAML }

Descrição

Este comando mostra o plano de execução que o planejador do PostgreSQL gera para a instrução especificada. O plano de execução mostra como as tabelas referenciadas pela instrução serão verificadas — por varredura sequencial simples, varredura de índice, etc. — e se forem especificadas várias tabelas, quais algoritmos de junção serão usados para juntar as linhas das diferentes tabelas.

A parte mais importante do que é mostrado é o custo estimado de execução da instrução, representando a estimativa do planejador sobre quanto tempo levará para executar a instrução (medido em unidades de custo que são arbitrárias, mas convencionalmente significam acessos de página no disco). Na verdade, são mostrados dois números: o custo inicial antes que a primeira linha possa ser retornada, e o custo total para retornar todas as linhas. Para a maioria das consultas, o custo total é o que importa, mas em contextos como uma subconsulta com EXISTS, o planejador escolherá o menor custo inicial em vez do menor custo total (já que o executor irá parar após obter uma linha, de qualquer maneira). Além disso, se for limitado o número de linhas retornadas usando a cláusula LIMIT, o planejador fará uma interpolação apropriada entre os dois limites de custo para estimar qual plano é realmente o menos dispendioso.

A opção ANALYZE faz com que a instrução seja realmente executada, não apenas planejada. Em seguida, as estatísticas de tempo de execução real são adicionadas ao que é mostrado, incluindo o tempo decorrido total gasto em cada nó do plano (em milissegundos), e o número total de linhas que realmente retornou. Permite ver se as estimativas do planejador estão próximas da realidade.

Importante

Tenha em mente que a instrução é realmente executada quando a opção ANALYZE é usada. Embora o comando EXPLAIN irá descartar qualquer saída que o comando SELECT possa retornar, os outros efeitos colaterais da instrução acontecerão normalmente. Se for desejado usar o comando EXPLAIN ANALYZE com uma instrução INSERT, UPDATE, DELETE, MERGE, CREATE TABLE AS ou EXECUTE, sem permitir que o comando afete os dados, deverá ser usada a seguinte abordagem:

BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;

Parâmetros

ANALYZE

Executa o comando e mostra os tempos de execução reais, e outras estatísticas. Este parâmetro tem como valor padrão FALSE.

VERBOSE

Mostra informações adicionais sobre o plano. Especificamente, inclui a lista de colunas de saída para cada nó na árvore do plano, os nomes das tabela e funções qualificados pelo esquema, os rótulos das variáveis nas expressões com o alias das tabelas, o nome de cada gatilho para o qual as estatísticas são mostradas. O identificador da consulta também será mostrado se um tiver sido calculado. Veja compute_query_id para obter mais detalhes. Este parâmetro tem como valor padrão FALSE.

COSTS

Inclui informações sobre o custo estimado da inicialização, e o custo total de cada nó do plano, bem como o número estimado de linhas e a largura estimada de cada linha. Este parâmetro tem como valor padrão TRUE.

SETTINGS

Inclui informações sobre os parâmetros de configuração. Especificamente, inclui as opções que afetam o planejamento da consulta com valor diferente do valor padrão nativo. Este parâmetro tem como valor padrão FALSE.

GENERIC_PLAN

Permita que a instrução contenha marcadores de posição para parâmetros, como $1, e gere um plano genérico que não dependa dos valores desses parâmetros. Veja PREPARE para obter detalhes sobre os planos genéricos e os tipos de instruções que oferecem suporte para parâmetros. Este parâmetro não pode ser usado em conjunto com ANALYZE. Este parâmetro tem como valor padrão FALSE.

BUFFERS

Inclui informações sobre o uso de área de armazenamento temporário (buffer). Especificamente, inclui o número de blocos compartilhados encontrados, lidos, sujados e escritos, o número de blocos locais encontrados, lidos, sujados e escritos, o número de blocos temporários lidos e escritos, e o tempo gasto lendo e escrevendo blocos de arquivos de dados, blocos locais e blocos de arquivos temporários (em milissegundos), se track_io_timing estiver ativo. Encontrado (hit) significa que a leitura foi evitada, porque o bloco foi encontrado no cache quando necessário. Os blocos compartilhados contêm dados de tabelas e índices regulares; os blocos locais contêm dados de tabelas e índices temporários; enquanto os blocos temporários contêm dados de trabalho de curto prazo usados em ordenações, hashes, nós de plano Materialize, e casos semelhantes. O número de blocos sujados indica o número de blocos previamente não sujados, que foram alterados por esta consulta; enquanto o número de blocos escritos indica o número de blocos sujados previamente removidos do cache por este processo servidor durante o processamento da consulta. O número de blocos mostrados para um nó de nível superior inclui aqueles usados por todos os seus nós filhos. No formato de texto, são mostrados apenas os valores diferentes de zero. São incluídas automaticamente as informações sobre buffer quando é usado ANALYZE.

SERIALIZE

Inclui informações sobre o custo de serialização dos dados de saída da consulta, ou seja, a conversão para formato de texto ou binário para envio ao cliente. Isto pode representar uma parte significativa do tempo necessário para a execução regular da consulta, caso as funções de saída do tipo de dados sejam dispendiosas ou se os valores TOAST precisarem ser buscados em um armazenamento externo. O comportamento padrão do comando EXPLAIN, SERIALIZE NONE, não realiza estas conversões. Se for especificado SERIALIZE TEXT ou SERIALIZE BINARY, serão realizadas as conversões apropriadas e o tempo gasto para isto será medido. (a menos que seja especificado TIMING OFF). Se também for especificada a opção BUFFERS, todos os acessos ao buffer envolvidos nas conversões também serão contabilizados. Porém, em nenhum caso, , o comando EXPLAIN irá enviar efetivamente os dados resultantes ao cliente; portanto, os custos de transmissão de rede não podem ser investigados dessa forma. A serialização só pode ser ativada quando ANALYZE também estiver ativada. Se for escrito SERIALIZE sem nenhum argumento, será assumido TEXT.

WAL

Inclui informações sobre a geração de registros do WAL. Especificamente, inclui o número de registros, o número de imagens de página inteira (full page images/fpi), a quantidade de WAL gerada em bytes e o número de vezes que os buffers do WAL ficaram cheios. No formato de texto, são mostrados apenas os valores diferentes de zero. Este parâmetro só poderá ser usado quando ANALYZE também for ativado. Este parâmetro tem como valor padrão FALSE.

TIMING

Inclui na saída o tempo real de inicialização, e o tempo gasto em cada nó. A sobrecarga de ler repetidamente o relógio do sistema pode diminuir muito a velocidade da consulta em alguns sistemas, portanto, pode ser útil definir este parâmetro como FALSE quando são necessárias apenas as contagens de linhas reais, e não os tempos exatos. O tempo de execução de toda a instrução é sempre medido, mesmo quando a cronometragem no nível do nó é desativada com esta opção. Este parâmetro só pode ser usado quando ANALYZE também estiver ativo. Este parâmetro tem como valor padrão TRUE.

SUMMARY

Inclui o resumo das informações (por exemplo, informações de tempo total) após o plano da consulta. O resumo das informações é incluído por padrão quando ANALYZE é usado, mas não é incluído sempre por padrão, podendo ser incluído usando esta opção. O tempo de planejamento no comando EXPLAIN EXECUTE inclui o tempo necessário para obter o plano do cache, e o tempo necessário para o replanejamento, se necessário.

MEMORY

Inclui informações sobre o consumo de memória durante a fase de planejamento da consulta. Especificamente, incluo a quantidade exata de armazenamento usada pelas estruturas de planejamento na memória, bem como a memória total considerando a sobrecarga de alocação. Este parâmetro tem como valor padrão FALSE.

FORMAT

Especifica o formato de saída, que pode ser TEXT, XML, JSON, ou YAML. A saída não textual contém as mesmas informações que o formato de saída textual, mas é mais fácil para os programas analisarem. Este parâmetro tem como valor padrão TEXT.

booleano

Especifica se a opção selecionada deve ser ativada ou desativada. Pode ser escrito TRUE, ON ou 1 para ativar a opção, e FALSE, OFF ou 0 para desativar a opção. O valor booleano também pode ser omitido, sendo então assumido como TRUE.

instrução

Qualquer instrução SELECT, INSERT, UPDATE, DELETE, MERGE, VALUES, EXECUTE, DECLARE, CREATE TABLE AS ou CREATE MATERIALIZED VIEW AS, cujo plano de execução se deseja ver.

Saídas

O resultado do comando é uma descrição textual do plano selecionado para a instrução, opcionalmente anotado com estatísticas de execução. Em Uso do comando EXPLAIN estão descritas as informações fornecidas.

Notas

Para permitir que o planejador de consultas do PostgreSQL tome decisões bem informadas ao otimizar as consultas, os dados da tabela pg_statistic devem estar atualizados para todas as tabelas usadas na consulta. Normalmente, o Autovacuum cuida disso automaticamente. Mas se a tabela teve recentemente alterações substanciais em seu conteúdo, talvez seja necessário executar o comando ANALYZE manualmente, em vez de esperar que a limpeza automática atualize as alterações.

Para medir o custo do tempo de execução de cada nó no plano de execução, a implementação corrente do comando EXPLAIN ANALYZE adiciona uma sobrecarga de criação de perfil à execução da consulta. Como resultado, a execução do comando EXPLAIN ANALYZE em uma consulta às vezes pode levar muito mais tempo do que executar a consulta normalmente. A quantidade de sobrecarga depende da natureza da consulta, bem como da plataforma que está sendo usada. O pior caso ocorre para os nós do plano que, por si só, requerem muito pouco tempo de execução, e em máquinas que possuem chamadas de sistema operacional relativamente lentas para obter a hora do dia.

Exemplos

Para mostrar o plano de uma consulta simples em uma tabela com uma única coluna do tipo inteiro com 10.000 linhas:

EXPLAIN SELECT * FROM foo;

                       QUERY PLAN
---------------------------------------------------------
 Seq Scan on foo  (cost=0.00..155.00 rows=10000 width=4)
(1 linha)

A seguir está a mesma consulta, com a saída formatada em JSON:

EXPLAIN (FORMAT JSON) SELECT * FROM foo;

           QUERY PLAN
--------------------------------
 [                             +
   {                           +
     "Plan": {                 +
       "Node Type": "Seq Scan",+
       "Relation Name": "foo", +
       "Alias": "foo",         +
       "Startup Cost": 0.00,   +
       "Total Cost": 155.00,   +
       "Plan Rows": 10000,     +
       "Plan Width": 4         +
     }                         +
   }                           +
 ]
(1 linha)

Se houver um índice e for usada uma consulta com uma condição WHERE indexável, o comando EXPLAIN poderá mostrar um plano diferente:

EXPLAIN SELECT * FROM foo WHERE i = 4;

                         QUERY PLAN
--------------------------------------------------------------
 Index Scan using fi on foo  (cost=0.00..5.98 rows=1 width=4)
   Index Cond: (i = 4)
(2 linhas)

A seguir está a mesma consulta, mas no formato YAML:

EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4';

          QUERY PLAN
-------------------------------
 - Plan:                      +
     Node Type: "Index Scan"  +
     Scan Direction: "Forward"+
     Index Name: "fi"         +
     Relation Name: "foo"     +
     Alias: "foo"             +
     Startup Cost: 0.00       +
     Total Cost: 5.98         +
     Plan Rows: 1             +
     Plan Width: 4            +
     Index Cond: "(i = 4)"
(1 linha)

O formato XML fica como exercício para o leitor.

A seguir está o mesmo plano, com as estimativas de custos suprimidas:

EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;

        QUERY PLAN
----------------------------
 Index Scan using fi on foo
   Index Cond: (i = 4)
(2 linhas)

A seguir está exemplo de um plano de consulta para uma consulta que utiliza uma função de agregação:

EXPLAIN SELECT sum(i) FROM foo WHERE i < 10;

                             QUERY PLAN
-------------------------------------------------------------------​--
 Aggregate  (cost=23.93..23.93 rows=1 width=4)
   ->  Index Scan using fi on foo  (cost=0.00..23.92 rows=6 width=4)
         Index Cond: (i < 10)
(3 linhas)

A seguir está um exemplo de como usar o comando EXPLAIN EXECUTE para mostrar o plano de execução de uma consulta preparada:

PREPARE query(int, int) AS SELECT sum(bar) FROM test
    WHERE id > $1 AND id < $2
    GROUP BY foo;

EXPLAIN ANALYZE EXECUTE query(100, 200);

                           QUERY PLAN
--------------------------------------------------------------
 HashAggregate  (cost=10.77..10.87 rows=10 width=12) ↵
                (actual time=0.043..0.044 rows=10.00 loops=1)
   Group Key: foo
   Batches: 1  Memory Usage: 24kB
   Buffers: shared hit=4
   ->  Index Scan using test_pkey on test  ↵
         (cost=0.29..10.27 rows=99 width=8) ↵
         (actual time=0.009..0.025 rows=99.00 loops=1)
         Index Cond: ((id > 100) AND (id < 200))
         Index Searches: 1
         Buffers: shared hit=4
 Planning Time: 0.244 ms
 Execution Time: 0.073 ms
(10 linhas)

Obviamente, os números específicos mostrados aqui dependem do conteúdo real das tabelas envolvidas. Note também que os números, e até mesmo a estratégia de consulta selecionada, podem variar entre as versões do PostgreSQL devido a melhorias no planejador. Além disso, o comando ANALYZE usa amostragem aleatória para estimar as estatísticas dos dados; portanto, é possível que as estimativas de custo sejam alteradas após uma nova execução do comando ANALYZE, mesmo que a distribuição real dos dados na tabela não tenha sido alterada.

Note que o exemplo anterior mostrou um plano personalizado para valores de parâmetro específicos fornecidos em EXECUTE. Também se pode querer ver o plano genérico para uma consulta parametrizada, o que pode ser feito com GENERIC_PLAN:

EXPLAIN (GENERIC_PLAN)
  SELECT sum(bar) FROM test
    WHERE id > $1 AND id < $2
    GROUP BY foo;

                        QUERY PLAN
----------------------------------------------------------
 HashAggregate  (cost=26.79..26.89 rows=10 width=12)
   Group Key: foo
   ->  Index Scan using test_pkey on test  ↵
         (cost=0.29..24.29 rows=500 width=8)
         Index Cond: ((id > $1) AND (id < $2))
(4 linhas)

Neste caso, o analisador inferiu corretamente que $1 e $2 deveriam ter o mesmo tipo de dados que id, portanto, a falta de informações sobre o tipo de dados do parâmetro do comando PREPARE não era um problema. Em outros casos, pode ser necessário especificar explicitamente os tipos de dados para os símbolos dos parâmetros, o que pode ser feito por meio de conversão de tipo de dados, por exemplo:

EXPLAIN (GENERIC_PLAN)
  SELECT sum(bar) FROM test
    WHERE id > $1::integer AND id < $2::integer
    GROUP BY foo;

Conformidade

Não existe o comando EXPLAIN definido no padrão SQL.

A seguinte sintaxe era usada antes da versão 9.0 do PostgreSQL e ainda tem suporte:

EXPLAIN [ ANALYZE ] [ VERBOSE ] instrução

Note que, nesta sintaxe, as opções devem ser especificadas exatamente na ordem mostrada.

Veja também

ANALYZE