Índices GIN para FTS
Índices GIN tornam tsvector @@ tsquery rápidos em escala. Construa em uma coluna tsvector armazenada, ajuste fastupdate e gin_pending_list_limit, e planeje a manutenção após importações em massa.
Receita
-- Preferencial: indexar coluna tsvector armazenada
CREATE INDEX CONCURRENTLY articles_fts_gin
ON articles USING gin (search_vector);
-- Verificar uso do índice
EXPLAIN (COSTS OFF)
SELECT id FROM articles
WHERE search_vector @@ plainto_tsquery('english', 'postgresql index');
-- Bitmap Index Scan on articles_fts_ginQuando usar isso: A latência de busca excede seu SLO em scans sequenciais, ou EXPLAIN mostra Seq Scan em filtros @@.
Exemplo de Trabalho
-- Padrão de carga em massa com indexação adiada
BEGIN;
ALTER TABLE articles DROP CONSTRAINT IF EXISTS articles_pkey;
-- (use tabela de staging UNLOGGED em pipelines reais)
TRUNCATE articles RESTART IDENTITY;
COPY articles (title, body) FROM '/tmp/articles.csv' CSV HEADER;
-- search_vector é GENERATED STORED; reconstrua o índice após a carga em massa
COMMIT;
-- Reconstruir GIN após importação grande (mais rápido que incremental para algumas cargas de trabalho)
REINDEX INDEX CONCURRENTLY articles_fts_gin;
ANALYZE articles;
SELECT pg_size_pretty(pg_relation_size('articles_fts_gin')) AS gin_size;O que isso demonstra:
tsvectorgerado permanece atual durante o COPYREINDEX CONCURRENTLYevita longos bloqueios de escrita após a importaçãoANALYZEatualiza estatísticas para a escolha entre bitmap e seq scan- Monitoramento de tamanho previne surpresas de disco
Mergulho Profundo
GIN vs GiST para FTS
| Método de acesso | Tempo de construção | Velocidade da consulta | Custo de atualização | Escolha típica para FTS |
|---|---|---|---|---|
| GIN | Mais lento, maior | Leituras mais rápidas | Custo de inserção mais alto | Padrão para busca |
| GiST | Construção mais rápida | Leituras mais lentas | Custo de inserção mais baixo | Raro para FTS |
A documentação do PostgreSQL recomenda GIN para tsvector, a menos que uma carga de trabalho de micro-atualizações com muitas escritas prove que GiST é melhor em benchmarks.
Padrões de Definição de Índice
-- Coluna única
CREATE INDEX ON docs USING gin (doc_tsv);
-- Índice parcial apenas para conteúdo publicado
CREATE INDEX docs_published_fts ON docs USING gin (doc_tsv)
WHERE status = 'published';
-- Cargas de trabalho combinadas de jsonb + fts: índices separados, não mesclarfastupdate e Lista Pendente
-- fastupdate por índice (PostgreSQL 9.5+)
ALTER INDEX articles_fts_gin SET (fastupdate = on);
SHOW gin_pending_list_limit; -- configuração do cluster, padrão 4MBA lista pendente agrupa pequenas inserções antes de mesclar na árvore GIN principal. Importações grandes podem se beneficiar de fastupdate = off durante a carga, e depois reindexar.
Comandos de Manutenção
-- Após importação em massa ou atualização de versão
REINDEX INDEX CONCURRENTLY articles_fts_gin;
-- Índices FTS da tabela inteira
REINDEX TABLE CONCURRENTLY articles;
-- Verificação de bloat (simplificada)
SELECT indexrelid::regclass,
pg_size_pretty(pg_relation_size(indexrelid))
FROM pg_stat_user_indexes
WHERE indexrelid::regclass::text LIKE '%fts%';Interação com Autovacuum
UPDATE pesado em colunas de texto regenera tsvector e causa churn nas páginas GIN. Ajuste o autovacuum em tabelas de busca:
ALTER TABLE articles SET (
autovacuum_vacuum_scale_factor = 0.02,
autovacuum_analyze_scale_factor = 0.01
);Armadilhas
- Indexar expressão sem garantia IMMUTABLE - Alguns wrappers de
to_tsvectorfalham na criação do índice. Correção: Coluna gerada armazenada ou coluna mantida por trigger. - CREATE INDEX sem CONCURRENTLY - Bloqueia escritas em tabelas grandes. Correção: Sempre use
CONCURRENTLYem produção. - Esqueceu ANALYZE - O planejador escolhe
seq scanapesar do índice. Correção: ExecuteANALYZEapós reindexar; verifiqueenable_bitmapscan. - Consultas com muito OR pulam o índice -
BitmapOrde múltiplos scans GIN ainda é OK; seletividade muito baixa pode resultar emseq scan. Correção: Aumenterandom_page_costapenas após medição. - Bloat na lista pendente - Pequenas inserções frequentes incham a lista pendente. Correção:
VACUUMperiódico ougin_clean_pending_list()em versões suportadas. - Reindexar durante o pico -
REINDEX CONCURRENTLYainda consome I/O. Correção: Agende janela de manutenção; limite workers paralelos.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Índice GiST | Taxa de escrita extrema, corpus minúsculo | Busca com muitas leituras domina |
| Sem índice (seq scan) | < 50k linhas, busca apenas administrativa | Busca voltada ao usuário em escala |
| GIN particionado por intervalo de tempo | Busca em arquivo de séries temporais | Consulta uniforme em todo o histórico |
| Índice de busca externo | Corpus além do FTS de nó único | Requisitos transacionais fortes |
FAQs
Qual o tamanho de um índice GIN?
Frequentemente 50-150% do tamanho da coluna `tsvector`, dependendo da cardinalidade do léxico. Meça com `pg_relation_size`.Falhas em CONCURRENTLY?
Índice inválido deixado para trás. Remova o índice inválido e tente novamente; verifique chaves duplicadas em restrições únicas durante a construção.Múltiplas colunas tsvector?
Índices GIN separados por coluna, a menos que as consultas sempre usem OR entre elas (raro).Incluir colunas?
GIN não suporta INCLUDE. Armazene campos de exibição no heap ou em um btree de cobertura em `id`.Atraso na replicação em REINDEX?
Réplicas reconstroem ao reproduzir ou via reindex manual; planeje manutenção coordenada.Confusão com jsonb_path_ops?
Isso é para a classe de operador GIN `jsonb`, não `tsvector`. Use os operadores `tsvector` padrão.fillfactor?
Geralmente o padrão 90. Diminuir raramente ajuda GIN; reindexar corrige bloat melhor.Construção paralela de índice?
O PostgreSQL suporta CREATE INDEX paralelo quando `max_parallel_maintenance_workers > 0`.Monitoramento?
Acompanhe `idx_scan`, `idx_blks_read` em `pg_stat_user_indexes` para índices FTS.Remover durante migração?
Use o padrão de recriação CONCURRENTLY em migrações de expandir-contração.Relacionados
- Noções Básicas de Full-Text Search - Visão geral do FTS
- tsvector & tsquery - conteúdo do vetor
- GIN e GiST - métodos de acesso
- REINDEX CONCURRENTLY - reconstruções online
- Melhores Práticas de Full-Text Search - checklist de importação em massa
Versões do Stack: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17), pgvector 0.8+, PostGIS 3.5+, pgbouncer 1.x, e Patroni 3.x.