PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

O que o PostgreSQL está me dizendo exatamente?


A parte que sempre achei confusa é o custo inicial versus o custo total. Eu pesquiso isso no Google toda vez que esqueço, o que me traz de volta aqui, o que não explica a diferença, e é por isso que estou escrevendo esta resposta. Isto é o que eu extraí do Postgres EXPLAIN documentação, explicada como eu a entendo.

Aqui está um exemplo de um aplicativo que gerencia um fórum:
EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

Aqui está a explicação gráfica do PgAdmin:



(Ao usar o PgAdmin, você pode apontar o mouse para um componente para ler os detalhes do custo.)

O custo é representado como uma tupla, por exemplo. o custo do LIMIT é cost=0.00..3.39 e o custo de escanear sequencialmente post é cost=0.00..15629.12 . O primeiro número na tupla é o custo inicial e o segundo número é o custo total . Porque eu usei EXPLAIN e não EXPLAIN ANALYZE , esses custos são estimativas, não medidas reais.
  • Custo inicial é um conceito complicado. Ele não representa apenas a quantidade de tempo antes que esse componente inicie . Ele representa a quantidade de tempo entre quando o componente começa a ser executado (lendo os dados) e quando o componente gera sua primeira linha .
  • Custo total é todo o tempo de execução do componente, desde o início da leitura dos dados até o término da gravação da saída.

Como complicação, os custos de cada nó "pai" incluem os custos de seus nós filhos. Na representação de texto, a árvore é representada por recuo, por exemplo. LIMIT é um nó pai e Seq Scan é seu filho. Na representação do PgAdmin, as setas apontam do filho para o pai - a direção do fluxo de dados - o que pode ser contra-intuitivo se você estiver familiarizado com a teoria dos grafos.

A documentação diz que os custos incluem todos os nós filhos, mas observe que o custo total do pai 3.39 é muito menor que o custo total de seu filho 15629.12 . O custo total não é inclusivo porque um componente como LIMIT não precisa processar toda a sua entrada. Veja o EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2; exemplo no Postgres EXPLAIN documentação.

No exemplo acima, o tempo de inicialização é zero para ambos os componentes, porque nenhum componente precisa fazer nenhum processamento antes de começar a escrever linhas:uma varredura sequencial lê a primeira linha da tabela e a emite. O LIMIT lê sua primeira linha e então a emite.

Quando um componente precisaria fazer muito processamento antes de poder começar a produzir qualquer linha? Há muitas razões possíveis, mas vejamos um exemplo claro. Aqui está a mesma consulta de antes, mas agora contendo um ORDER BY cláusula:
EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

E graficamente:



Mais uma vez, a varredura sequencial em post não tem custo de inicialização:ele começa a gerar linhas imediatamente. Mas a classificação tem um custo inicial significativo 23283.24 porque tem que ordenar a tabela inteira antes que possa gerar uma única linha . O custo total da classificação 23859.27 é apenas um pouco maior do que o custo inicial, refletindo o fato de que, uma vez que todo o conjunto de dados tenha sido classificado, os dados classificados podem ser emitidos muito rapidamente.

Observe que o tempo de inicialização do LIMIT 23283.24 é exatamente igual ao tempo de inicialização da classificação. Isso não ocorre porque LIMIT em si tem um alto tempo de inicialização. Na verdade, ele tem zero tempo de inicialização por si só, mas EXPLAIN acumula todos os custos dos filhos para cada pai, então o LIMIT tempo de inicialização inclui a soma dos tempos de inicialização de seus filhos.

Esse acúmulo de custos pode dificultar a compreensão do custo de execução de cada componente individual. Por exemplo, nosso LIMIT tem zero tempo de inicialização, mas isso não é óbvio à primeira vista. Por esse motivo, várias outras pessoas se conectaram ao explain.depesz.com, uma ferramenta criada por Hubert Lubaczewski (também conhecido como depesz) que ajuda a entender EXPLAIN por - entre outras coisas - subtraindo os custos filho dos custos pai. Ele menciona algumas outras complexidades em uma breve postagem no blog sobre sua ferramenta.