Performance

B-tree, GIN e BRIN: escolhendo o índice certo no PostgreSQL

PG Monitoring Team May 20, 2026 8 min de leitura

Usar o CREATE INDEX sem pensar te dá um B-tree toda vez — e o B-tree é a ferramenta errada para busca textual, JSONB, arrays e tabelas de séries temporais com bilhões de linhas. Conhecer os quatro tipos de índice do PostgreSQL é a diferença entre uma consulta que voa e uma que ignora seu índice por completo.

Não existe tamanho único

O PostgreSQL traz vários métodos de acesso de índice. Escolha errado e você não ganha velocidade ou paga 10× em disco e custo de escrita à toa. Os três que mais importam no dia a dia são B-tree, GIN e BRIN — e a pergunta decisiva é sempre a mesma: qual é o formato do dado e qual é o formato da consulta?

B-tree — o cavalo de batalha padrão

Usado automaticamente pelo CREATE INDEX. Perfeito para comparações de igualdade e faixa sobre valores escalares, e para ORDER BY.

CREATE INDEX idx_orders_created ON orders (created_at);
-- ajuda:  WHERE created_at > now() - interval '7 days'
--         ORDER BY created_at DESC
--         WHERE customer_id = 42  (igualdade)

Suporta índices multicoluna, em que a ordem das colunas importa: um índice em (a, b) ajuda WHERE a = ? e WHERE a = ? AND b = ?, mas não WHERE b = ? sozinho.

GIN — para valores que contêm muitos subvalores

Generalized Inverted Index. Use quando uma coluna guarda muitos itens pesquisáveis: documentos JSONB, arrays e vetores de busca textual.

-- Continência em JSONB
CREATE INDEX idx_doc_data ON documents USING gin (data jsonb_path_ops);
-- ajuda:  WHERE data @> '{"status": "active"}'

-- Busca textual (full-text)
CREATE INDEX idx_articles_fts ON articles
  USING gin (to_tsvector('portuguese', body));
-- ajuda:  WHERE to_tsvector('portuguese', body) @@ plainto_tsquery('postgres')

-- Pertencimento em array
CREATE INDEX idx_post_tags ON posts USING gin (tags);
-- ajuda:  WHERE tags @> ARRAY['sql']

Índices GIN são maiores e mais lentos para atualizar que o B-tree. Se você escreve com frequência, considere ajustar fastupdate e gin_pending_list_limit.

BRIN — índices minúsculos para tabelas enormes e naturalmente ordenadas

Block Range INdex. Em vez de indexar cada linha, ele guarda o mínimo/máximo por faixa de blocos. O resultado é surpreendentemente pequeno — muitas vezes megabytes para uma tabela de um bilhão de linhas — mas só funciona quando a coluna se correlaciona com a ordem física das linhas (pense em logs append-only ordenados por tempo).

CREATE INDEX idx_events_time_brin ON events
  USING brin (created_at) WITH (pages_per_range = 128);
-- ajuda:  WHERE created_at BETWEEN '2026-01-01' AND '2026-02-01'
-- em tabela append-only onde as linhas chegam em ordem de tempo

Um índice BRIN pode ter 1/1000 do tamanho do B-tree equivalente. Em uma tabela de série temporal bem correlacionada ele entrega quase todo o benefício por uma fração do armazenamento e do custo de escrita. Em uma coluna com ordem aleatória, é inútil.

Tabela rápida de decisão

Sua consultaTipo de índice
=, <, >, BETWEEN, ORDER BY em escalarB-tree
JSONB @>, array contém, full-text @@GIN
Faixas em tabela enorme append-only / ordenada por tempoBRIN
Sobreposição de tipos geométricos/range, vizinho mais próximoGiST
Apenas igualdade simples, menor alternativa ao B-treeHash

O índice que você esqueceu

O custo oculto dos índices são os que ninguém usa: todo índice sem uso ainda deixa cada INSERT e UPDATE mais lento e incha os backups. O PG Monitoring relata o uso de cada índice (idx_scan) e sinaliza os que não são tocados há semanas, além dos índices faltantes que realmente ajudariam — quantificados em milissegundos economizados.

Related Articles

Ready to experience better PostgreSQL monitoring?

Join thousands of teams who switched from traditional tools to PG Monitoring's AI-powered platform.

Fale conosco