Pos Em Banco De Dados - Módulo de Pós-Graduação em Engenharia de Banco de Dados
Módulo de Pós-Graduação em Engenharia de Banco de Dados

O que éPOSITION no banco de dados (e por que todo mundo usa errado)

A função POSITION serve para encontrar a localização de uma substring dentro de uma string maior. Parece simples até você tentar usar em produção e descobrir que o resultado não é o que esperava. O padrão SQL define POSITION(substring IN string), mas na prática cada SGBD implementa isso de forma ligeiramente diferente, e isso causa dor de cabeça constante.

Pos em banco de dados: como funciona na prática

Em MySQL, PostgreSQL e SQL Server a sintaxe varia um pouco. MySQL e PostgreSQL aceitam POSITION(sub IN str) e também a versão com LOCATE(), que é mais flexível porque permite especificar o ponto de partida da busca. SQL Server obriga você a usar CHARINDEX() ou PATINDEX(). Se você escreve código que precisa rodar em mais de um banco, isso já é um problema logo de cara. Um detalhe que muitas pessoas ignoram: POSITION retorna 0 quando a substring não é encontrada. Zero significa "não existe", e não 1. Muitas queries defeituosas são escritas com a lógica invertida, testando se o resultado é diferente de NULL ao invés de diferente de zero. O resultado são filtros que nunca funcionam como esperado.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Também é importante saber que POSITION é case-sensitive na maioria dos bancos. Se sua string tem "Erro" e você busca "erro", vai retornar 0. Em PostgreSQL dá para contornar com POSITION(LOWER(sub) IN LOWER(str)). Em MySQL, depende do collation da coluna. Se o collation for _ci, a busca ignora case. Se for _cs, não ignora. Você precisa saber qual está usando antes de confiar no resultado. Já tive um caso específico em que uma view que calculava posições de tags em strings separadas por vírgula começou a retornar resultados errados depois de uma atualização de collation no banco. A consulta usava POSITION(',' IN campo) para encontrar separadores e extrair itens. A mudança de1_general_ci para utf8mb4_unicode_ci fez com que acentos passassem a ser tratados de forma diferente nas comparações, e_POSITION comeu caracteres especiais sem avisar. A correção foi trocar POSITION por LOCATE com COLLATE explícito em todas as referências da view. Levei cerca de três horas pra diagnosticar porque o sintoma era sutil — dados normais funcionavam, só strings com acento falhavam silenciosamente.

Alternativas que você provavelmente deveria estar usando

POSITION é útil, mas raramente é a melhor ferramenta quando o assunto é performance em grandes volumes. Se você precisa localizar strings repetidamente em tabelas com milhões de linhas, POSITION sozinho vai escalar mal porque exige leitura sequencial. Nesse cenário, funcionalidades como FULLTEXT INDEX no MySQL ou TSVECTOR no PostgreSQL fazem trabalho pesado muito mais rápido. Um contra-intuitivo que poucos mencionam: POSITION em colunas TEXT ou VARCHAR(MAX) pode ser extremamente caro em termos de I/O. Cada comparação força o banco a carregar a coluna inteira na memória de trabalho. Se você precisa buscar dentro de campos textuais longos, considere normalizar o dado — extrair os trechos que importa buscar para colunas menores e indexadas, e usar POSITION apenas nesses campos auxiliares. O ganho de performance costuma ser de uma ordem de grandeza, às vezes mais.

Outra armadilha comum é usar POSITION em expressões WHERE sem índice por baixo. Posições em WHERE são computações lineares que não aproveitam índices tradicionais. Se o filtro é parte crítica do query plan, pense em gerar uma coluna computada persistente ou um índice materializado. No PostgreSQL, expressions indexes funcionam bem pra isso. No MySQL, columns geradas com GENERATED ALWAYS AS resolvem o problema de forma elegante. O ponto principal é: POSITION resolve o problema conceitual corretamente, mas o custo prático depende do que vem antes e depois dela na query. Se você tratar POSITION como uma solução universal sem olhar o plano de execução, vai ter surpresa na produção.