Os quatro GUCs esquecidos do PostgreSQL que ainda revelam CPU e page faults por query
log_parser_stats, log_planner_stats, log_executor_stats e log_statement_stats datam de 2003, mas reportam algo que EXPLAIN ANALYZE e pg_stat_statements não mostram: o split entre CPU e espera de uma query.

log_parser_stats, log_planner_stats, log_executor_stats e log_statement_stats datam de 2003, mas reportam algo que EXPLAIN ANALYZE e pg_stat_statements não mostram: o split entre CPU e espera de uma query.
A série "All Your GUCs in a Row", publicada no Planet PostgreSQL↳PostgreSQL11 conteúdosPostgreSQL via SSL com GolangData · abr 20195 itens legais sobre data types do PostgreSQLData · mar 20195 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data →, dedicou um artigo aos quatro parâmetros de logging mais antigos que o PostgreSQL ainda carrega: log_parser_stats, log_planner_stats, log_executor_stats e log_statement_stats. São vestígios de 2003 (os nomes atuais vieram na versão 7.4), mais velhos que o próprio EXPLAIN ANALYZE (7.2) e bem anteriores a pg_stat_statements e auto_explain, ambos da 8.4. O texto os classifica com honestidade brutal: quando ligados no lugar errado, "produzem um log feito em grande parte de pontos de exclamação".
Ainda assim, para o DBA que precisa dissecar uma query específica, esses parâmetros reportam informação que nenhuma outra ferramenta do core entrega por statement. E é aí que eles deixam de ser curiosidade histórica.
O que eles fazem por baixo
Cada um é um booleano, off por padrão, exige contexto de superusuário. O mecanismo é simples ao ponto de ser rústico: o backend↳Back-end49 conteúdosIntegração front-end com backend: 7 decisões que evitam caos entre APIs, BFF e GraphQLDev (Back & Front) · abr 2026Como criar uma FAKE API REST para testes — JSONPlaceholderDev (Back & Front) · set 2025Construindo um aplicativo de bate-papo de IA simples com Spring AI e AngularDev (Back & Front) · jul 2025Ver tudo em Dev (Back & Front) → chama getrusage() antes e depois de um estágio da execução do statement e escreve a diferença no log, em nível LOG. A própria documentação chama isso de "um instrumento de profiling grosseiro", e o texto reforça o diagnóstico: é getrusage() com um printf() em volta, numa função que ainda carrega um comentário de código sobre quem toma café na DEC.
A divisão de trabalho entre os quatro:
| Parâmetro | Estágio coberto | Blocos por statement |
|---|---|---|
log_parser_stats | parser, parse analysis e rewriter | 3 (um por estágio) |
log_planner_stats | planner | 1 |
log_executor_stats | executor | 1 |
log_statement_stats | statement inteiro | 1 |
Como log_statement_stats mede o statement completo, ele se recusa a ser habilitado junto com qualquer um dos outros três, e vice-versa. O artigo aponta um detalhe revelador: o comentário no código-fonte admite que essa exclusão mútua não funciona direito quando os valores chegam via ALTER ROLE ... SET, e "ninguém se importou o suficiente para consertar".
O que aparece no log
A saída de um SELECT count(*) com log_statement_stats ligado:
LOG: QUERY STATISTICS
DETAIL: ! system usage stats:
! 0.178254 s user, 0.318332 s system, 5.021073 s elapsed
! [0.179736 s user, 0.318332 s system total]
! 126332 kB max resident size
! 784/248560 [784/248560] filesystem blocks in/out
! 0/2605 [0/3105] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 270/281 [272/282] voluntary/involuntary context switches
STATEMENT: select count(*) from tA leitura é o que importa: os números sem colchetes são o delta daquele estágio; os entre colchetes são o total do backend desde que ele iniciou; e o max resident size não é nem um nem outro, é uma marca de pico (high-water mark).
Por que isso ainda vale, e onde EXPLAIN ANALYZE não chega
Aqui está o argumento central do artigo, e o ponto que interessa a quem opera PostgreSQL em produção. EXPLAIN ANALYZE dá tempo de parede (wall time) e buffers. pg_stat_statements dá tempo de parede e buffers, agregados. Nenhum dos dois diz que os cinco segundos do exemplo acima foram meio segundo de CPU e quatro e meio de espera.
Essa distinção é decisiva no diagnóstico. Uma query que consome cinco segundos de wall time e queima CPU o tempo todo é um problema de plano, de índice ausente, de estimativa errada. Uma query que consome cinco segundos mas gasta CPU por meio segundo está esperando: I/O, lock, contenção de recurso. São incidentes de naturezas opostas, e o EXPLAIN ANALYZE sozinho não separa os dois. Os stats do executor separam.
O mesmo vale para page faults. Como observa o artigo, esses contadores revelam quando uma query está "gerando minor faults porque algo está alocando e liberando um work_mem grande dentro de um loop", padrão que passa despercebido nas ferramentas convencionais.
O uso correto, então, é cirúrgico. Numa sessão de superusuário:
SET log_executor_stats = on;
-- rode a query problemática aqui
SET log_executor_stats = off;A resposta fica no log. Não é para deixar ligado.
Três armadilhas antes de acreditar nos números
O artigo lista três ressalvas que o DBA precisa internalizar, sob pena de tirar conclusão errada de um número correto:
- Paralelismo distorce. O
getrusage()mede apenas o backend, e workers paralelos são processos separados. Uma query paralela reporta só a fatia do líder. No exemplo do artigo, o mesmocount(*)mostrou 0,03 s de CPU user com dois workers e 0,12 s sem nenhum, e "o número menor é o errado". - Protocolo estendido triplica os blocos. Todo driver moderno usa o extended protocol, e isso gera três blocos por statement, rotulados
PARSE MESSAGE,BIND MESSAGEeEXECUTE MESSAGE STATISTICS, em vez de um só. Quem lê o log precisa saber o que está olhando. log_error_verbosity = tersemata o DETAIL. Com essa configuração, sobra um log de cabeçalhosQUERY STATISTICSsem nada embaixo, "um tipo especial de nada".
A alternativa moderna: pg_stat_kcache
Para quem quer esses contadores em todas as queries em vez de uma isolada, a resposta não é ligar os GUCs no postgresql.conf. É a extensão pg_stat_kcache, que coleta os mesmos campos do getrusage() e os agrega por query ID, lado a lado com o pg_stat_statements. Nas palavras do artigo, é o que esses quatro parâmetros "seriam se tivessem sido projetados depois de 2009 em vez de antes de 1997".
Essa é a recomendação prática que fica para o dia a dia: quem monitora frota de PostgreSQL e quer visibilidade contínua de CPU user/system e page faults por query ID deve avaliar pg_stat_kcache, não os GUCs legados.
O veredicto
A orientação final do artigo é direta: deixe os quatro em off no postgresql.conf. O habitat deles é uma sessão de superusuário, para um único statement, seguida de SET de volta para off. Em qualquer outro lugar, o custo (poluição de log, distorção por paralelismo, blocos triplicados) supera o benefício.
O valor real desses parâmetros para o DBA brasileiro é conceitual e pontual: entender que existe uma ferramenta no core capaz de separar CPU de espera numa query suspeita, antes de escalar hardware ou reescrever a query no escuro. Diagnóstico correto começa por saber o que a query está realmente fazendo com o tempo dela, e às vezes um GUC de 2003, usado por trinta segundos, responde a pergunta que o EXPLAIN ANALYZE não responde.
Fonte: Planet PostgreSQL
Este artigo foi escrito por Roberto Diniz, colunista de banco de dados do iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters. Saiba como produzimos no expediente.











Comentários
Ninguém comentou ainda. Começa a conversa?