O que EXPLAIN e EXPLAIN ANALYZE mostram

Prévia grátis 3 min de leitura

Uma camada diferente de um log de consultas repetidas

"Querying: detecção N+1" ensinou a ler o log/development.log deste app atrás de uma rajada de consultas repetidas. Era um rótulo que aparece dezenas de vezes, igual exceto por um id que varia. Isso é um padrão entre várias consultas. Este curso começa um nível abaixo, no que o plano de execução de uma única consulta diz quando você a roda uma vez e lê com atenção. Um padrão de log nunca mostra essa camada. Um não substitui o outro. Uma rajada no log diz que um formato de consulta rodou vezes demais; um plano diz se cada uma dessas execuções fez o trabalho de forma eficiente.

EXPLAIN: o plano, sem executar nada

O EXPLAIN pergunta ao planejador de consultas do Postgres o que ele faria com um comando SQL e imprime a árvore de operações escolhida, sem executar nenhuma delas. Todo número de um EXPLAIN simples é uma estimativa, feita a partir de estatísticas que o Postgres guarda sobre cada tabela, e nunca uma medição. Por isso é seguro rodá-lo sobre uma escrita, um UPDATE ou DELETE, sem que a escrita aconteça.

EXPLAIN ANALYZE: o plano, mais o que aconteceu

O EXPLAIN ANALYZE planeja a consulta do mesmo jeito, depois a executa, medindo o tempo de cada operação e contando as linhas que cada uma produziu. A saída mantém a mesma árvore, com as estimativas de custo, e acrescenta as medições actual time=... e rows=... ao lado de cada nó. Este curso usa essa versão do começo ao fim, porque o objetivo é comparar o que o planejador esperava com o que aconteceu. Essa comparação exige que a consulta tenha rodado.

Vale dizer uma consequência com clareza: EXPLAIN ANALYZE num INSERT, UPDATE ou DELETE executa a escrita. Por isso, toda captura deste curso roda uma leitura, e nunca uma escrita.

Rodando contra o banco deste app

Este curso captura cada plano no banco de desenvolvimento deste app pelo bin/rails runner, a mesma ferramenta que "Querying: detecção N+1" usou para capturar a saída do log:

sql = Catalog::Course.active.order(:position).to_sql
plan = ActiveRecord::Base.connection.select_all("EXPLAIN (ANALYZE, BUFFERS) #{sql}").rows
plan.each { |row| puts row.first }

Catalog::Course.active é um scope deste app, scope :active, -> { where(active: true) }. O .to_sql transforma a relação do ActiveRecord no SQL que o Postgres vai rodar. Envolvê-lo em EXPLAIN (ANALYZE, BUFFERS) acrescenta contagens de leitura de páginas, Buffers: shared hit=N, ao lado do tempo. O banco de desenvolvimento roda o PostgreSQL 18, enquanto a produção roda a imagem postgres:16. As versões mais novas imprimem alguns detalhes a mais (contagens rows= com casas decimais, por exemplo). As próximas três aulas rodam esse padrão em três consultas que este app usa e leem a saída.

O que este curso cobre

  1. A anatomia básica de um plano: tipos de scan, cost=, actual time= e rows=, lidos numa consulta à tabela courses deste app.
  2. Um caso em que um índice é usado e o Postgres ainda acrescenta uma etapa de ordenação separada, e por quê.
  3. Ler um join e uma agregação juntos, numa consulta de ranking entre domínios que este app rodava em toda página de perfil, depois substituída por snapshots pré-calculados.
  4. Um caso pego ao vivo em que a estimativa de linhas do planejador estava errada, e o que a corrige.
  5. Pedir a uma ferramenta de IA que leia bem um plano, a partir da disciplina de "colar, não parafrasear" dos cursos de IA anteriores.
  6. Juntar o fluxo, de um plano capturado bruto a uma conclusão verificada.
Aula 1 de 7 · grátis

Continue com a aula 2

Lendo a anatomia de um plano: tipos de scan, custo, e linhas

Lê o plano da consulta de cursos ativos: um Seq Scan, um Sort, estimativas de custo e linhas medidas.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...