12 segundos para ler 3 000 linhas. Ops
Duas coisas salvaram-me esta semana: o EXPLAIN ANALYZE e o SET LOCAL enable_nestloop = off. O primeiro é a maneira que o Postgres tem de te mostrar o que o planeador de consultas realmente fez, não o que acha que vai fazer, mas tempos de execução reais, contagens de linhas reais, estratégias de junção reais. O segundo é uma sobreposição com âmbito de transação que diz ao planeador “não podes usar junções de ciclos aninhados nesta consulta”. Embrulhas num bloco BEGIN / COMMIT, aplica-se a essa execução e não passa para mais nada na ligação. É feio. É um instrumento brusco. Deu-me uma aceleração de 16× numa consulta em que três reescritas de SQL cada vez mais sofisticadas pioraram tudo.
O problema: o nó WindowAgg do Postgres, o que executa o teu ROW_NUMBER(), RANK(), SUM() OVER (...), não propaga estimativas de cardinalidade. O planeador avalia o resultado da função de janela, entra em pânico e estima rows=1. Se essa função de janela está dentro de uma vista que alimenta junções a jusante, essa única estimativa errada espalha-se em cascata por todas as decisões de junção seguintes.
O planeador escolhe ciclos aninhados porque os ciclos aninhados são ótimos para uma linha. Tu não tens uma linha. Tens milhares. Cada iteração volta a percorrer uma vista com vários milhares de linhas. Geram-se milhões de linhas intermédias que são logo descartadas. A tua consulta demora 12 segundos sobre 3 000 linhas de origem e perdes uma hora da tua vida a tentar reescritas que falham todas, porque o erro de estimativa de fundo envenena todas as formas de consulta que lhe atiras. O SET LOCAL enable_nestloop = off força junções por hash, que devoram os dados reais em menos de um segundo. É uma limitação conhecida, sem solução limpa no Postgres gerido. Às vezes a correção pragmática é a certa.