CTO no Integrar Plus • Publicado em 20 de September de 2026
Toda vez que surge uma ferramenta prometendo transformar o PostgreSQL em um motor de busca textual completo, a reação da comunidade de desenvolvimento se divide em dois extremos previsíveis. De um lado, defensores do banco relacional bradam que a documentação oficial já resolve o problema com tsvector e índices GIN desde versões remotas, sugerindo que qualquer complexidade extra decorre de pura preguiça de leitura. Do outro, uma onda de entusiasmo saúda anúncios recentes, como o Tin da PlanetScale e outras extensões baseadas no algoritmo BM25, como a certidão de óbito definitiva do Elasticsearch ou do OpenSearch. Afinal, quem não gostaria de desligar uma máquina virtual dedicada só para busca e manter tudo sob o mesmo teto transacional?
Eu entendo a tentação de simplificar a arquitetura. Gerencio servidores próprios para rodar aplicações em Ruby on Rails com PostgreSQL, e eliminar processos em segundo plano, rotinas frágeis de sincronização e nós extras de JVM é o sonho de qualquer equipe enxuta. No entanto, quando vejo essa discussão ganhar força, percebo que a maior parte dos argumentos ignora solenemente como o subsistema de armazenamento e o gerenciador de memória do PostgreSQL se comportam sob pressão mista de leitura e escrita. Aposentar um cluster externo para colocar busca textual pesada dentro da sua instância primária de banco costuma trocar um problema de sincronização por uma crise de concorrência e exaustão de I/O que derruba o sistema inteiro.
O primeiro erro comum é achar que o tsvector nativo do PostgreSQL entrega a mesma experiência que um mecanismo moderno de busca. A busca nativa tradicional oferece correspondência booleana competente com pesos estáticos, mas sofre bastante quando você precisa de ordenação probabilística baseada em relevância, como o algoritmo BM25, ou quando lida com vocabulários dinâmicos e grandes massas de texto semântico. Além disso, índices GIN em tabelas com taxa razoável de escrita geram uma dor de cabeça constante: atualizações em colunas indexadas exigem manutenção pesada no índice invertido, produzem inchaço rápido de páginas e exigem configurações agressivas de autovacuum para evitar lentidão catastrófica nas consultas corriqueiras.
As novas propostas que trazem BM25 para dentro do PostgreSQL, como o Tin e outras implementações similares, tentam preencher essa lacuna de relevância. A premissa parece imbatível: você usa a sintaxe SQL convencional, evita ferramentas intermediárias de replicação como Kafka ou rotinas de Change Data Capture, e ganha relevância de busca textual na mesma consulta que filtra registros por permissões de usuário ou tenant. O problema surge no instante em que você olha para os recursos físicos da máquina onde essa mágica acontece.
Um motor como Lucene ou Elasticsearch consome memória e disco de maneira muito diferente de um banco relacional transacional. Em um ambiente OLTP, você dimensiona a memória compartilhada (shared_buffers) e o cache do sistema operacional para manter tabelas quentes, índices B-Tree curtos e páginas de controle carregadas, garantindo que leituras e escritas por chave primária ocorram em frações de milissegundo. Quando você introduz um índice textual amplo que precisa percorrer listas invertidas extensas para ranquear termos raros, as leituras aleatórias começam a varrer o cache do sistema operacional.
O resultado prático é a expulsão silenciosa das páginas quentes do seu banco de dados. Uma busca textual mais ampla ou mal formatada por um usuário final exige carregar dezenas de megabytes de estruturas de termos do disco. Se essas estruturas competem pelo mesmo espaço de memória RAM que atende às transações normais da aplicação web, o I/O do disco dispara, a fila de espera do PostgreSQL aumenta e as requisições normais da API ou da interface começam a acumular tempo de espera. Em uma VPS com discos NVMe e memória finita, esse comportamento gera picos de latência que nenhum ajuste fino de pool de conexões consegue remediar.
Existe também um abismo operacional que poucos consideram ao avaliar extensões de busca textual anunciadas por plataformas em nuvem: a portabilidade real da solução. Muitas dessas extensões de alto desempenho são desenhadas para infraestruturas gerenciadas específicas, com armazenamento desacoplado ou camadas de cache proprietárias. Quando você vai procurar o código para compilar em uma distribuição Linux comum dentro da sua própria máquina, encontra apenas versões de testes, módulos com recursos limitados ou projetos que dependem de licenças restritivas. A promessa de simplicidade do SQL acaba virando dependência direta de um fornecedor de nuvem particular.
+-------------------------------------------------------------------+
| Instância Única (VPS) |
| |
| +-----------------------+ +-----------------------+ |
| | Carga OLTP (Web) | | Busca BM25 / FTS | |
| | INSERT / UPDATE | | Varredura de Índice | |
| +-----------+-----------+ +-----------+-----------+ |
| | | |
| v v |
| [ Buffer Pool / Shared Buffers ] <---> [ Cache do Kernel (Page) ]|
| | |
| Disputa agressiva de RAM |
| | |
| v |
| [ I/O de Disco Compartilhado ] |
| (Gargalo de latência e filas) |
+-------------------------------------------------------------------+
A discussão levantada por quem opera bancos no dia a dia não deveria ser sobre qual tecnologia é teoricamente mais elegante, mas sim sobre o isolamento de falhas e consumo de recursos. Eu costumo adotar uma divisão bastante pragmática sobre quando manter a busca no PostgreSQL e quando aceitar a complexidade de um serviço separado:
Trocar um cluster de Elasticsearch por uma extensão milagrosa no banco principal pode parecer uma vitória de produtividade nas primeiras semanas de projeto. O código da aplicação fica mais limpo, a gem no Rails quase não precisa de configuração e o processo de deploy continua enxuto. O problema dessa abordagem é que a fatura nunca chega durante o desenvolvimento. Ela chega na sexta-feira à tarde, quando o volume de acessos sobe, um usuário resolve fazer três buscas complexas simultâneas e o banco primário esgota a capacidade de resposta por estar ocupado demais ordenando termos em vez de confirmar transações bancárias ou salvar novos pedidos.
A busca textual integrada no PostgreSQL tem avançado de forma admirável, e projetos que trazem algoritmos modernos para o ecossistema merecem atenção cuidadosa. Mas acreditar que essas extensões eliminam a necessidade de motores especializados em qualquer escala é confundir conveniência sintática com realidade física de hardware. Antes de apagar seus nós de busca e colocar toda a carga no nó mestre do banco, meça o impacto de concorrência e avalie se o seu negócio realmente aguenta ter as transações mais importantes da empresa disputando fatias de disco com um ranqueamento de texto.
CTO e arquiteto full stack especializado em Ruby on Rails, Vue.js, sistemas multi-tenant e infraestrutura distribuída.