PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

unaccent() impedindo o uso de índice no Postgres

Variante IMUTÁVEL de unaccent()


Para esclarecer a desinformação na atualmente aceita, resposta incorreta :
Os índices de expressão permitem apenas IMMUTABLE funções (por razões óbvias) e unaccent() é apenas STABLE . A solução que você sugeriu no comentário também é problemático. Explicação detalhada e uma solução adequada para isso :

Dependendo do conteúdo de tags->name pode ser útil adicionar unaccent() ao índice de expressão, mas isso é ortogonal à pergunta por que o índice não estava sendo usado:

Problema/solução real


O operador LIKE em sua consulta está sutilmente errado (provavelmente). Você não quiser interpretar 'Weststrasse' como padrão de pesquisa, você deseja corresponder à string (normalizada) como está. Substitua pelo = operador, e você verá uma varredura de índice (bitmap) com seu índice atual, independente da volatilidade da função de unaccent() :
SELECT * FROM germany.ways
WHERE lower(tags->'name') = lower(unaccent('unaccent','Weststrasse'))

Por quê?


O operando direito de LIKE é um padrão . O Postgres não pode usar um índice btree simples para correspondência de padrões ( exceções se aplicam ). Um LIKE com uma string simples como padrão (sem caracteres especiais) pode ser otimizada com uma verificação de igualdade no índice btree. Mas se houver caracteres especiais na string, este índice está fora.

Se houver um IMMUTABLE função à direita de LIKE , ele pode ser avaliado imediatamente e a referida otimização ainda é possível. De acordo com a documentação sobre Categorias de volatilidade de função :

O mesmo não é possível com uma menor volatilidade de função (STABLE ou VOLATILE ). É por isso que sua "solução" de fingir um IMMUTABLE unaccent() parecia funcionar, mas é realmente colocar batom em um porco.

Reiterar:
  • Se você quiser trabalhar com LIKE e padrões, use um índice de trigrama .
  • Se você não quiser trabalhar com LIKE e padrões, use o operador de igualdade =