PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

unaccent() empêche l'utilisation de l'index dans Postgres

Variante IMMUTABLE de unaccent()

Pour clarifier la désinformation dans la actuellement acceptée, réponse incorrecte :
Les index d'expression n'autorisent que IMMUTABLE fonctions (pour des raisons évidentes) et unaccent() est seulement STABLE . La solution que vous avez suggérée dans le commentaire est également problématique. Explication détaillée et solution appropriée pour ça :

Selon le contenu de tags->name il peut être utile d'ajouter unaccent() à l'expression index, mais c'est orthogonal à la question de savoir pourquoi l'index n'était pas utilisé :

Problème réel/solution

L'opérateur LIKE dans votre requête est subtilement erroné (probablement). Vous ne faites pas voulez interpréter 'Weststrasse' comme modèle de recherche, vous voulez faire correspondre la chaîne (normalisée) telle quelle. Remplacez par le = opérateur, et vous verrez un balayage d'index (bitmap) avec votre index actuel, indépendamment de la volatilité de la fonction de unaccent() :

SELECT * FROM germany.ways
WHERE lower(tags->'name') = lower(unaccent('unaccent','Weststrasse'))

Pourquoi ?

L'opérande droit de LIKE est un motif . Postgres ne peut pas utiliser un index btree simple pour la correspondance de modèle ( des exceptions s'appliquent ). Un LIKE avec une chaîne simple comme modèle (pas de caractères spéciaux) peut être optimisé avec un contrôle d'égalité sur l'index btree. Mais s'il y a des caractères spéciaux dans la chaîne, ceci l'index est sorti.

S'il y a un IMMUTABLE fonction à droite de LIKE , elle peut être évaluée immédiatement et ladite optimisation est encore possible. Par documentation sur les catégories de volatilité des fonctions :

La même chose n'est pas possible avec une moindre volatilité de la fonction (STABLE ou VOLATILE ). C'est pourquoi votre "solution" de simuler un IMMUTABLE unaccent() semblait fonctionner, mais c'est vraiment mettre du rouge à lèvres sur un cochon.

Pour réitérer :

  • Si vous souhaitez travailler avec LIKE et modèles, utilisez un index trigramme .
  • Si vous ne voulez pas travailler avec LIKE et les motifs, utilisez l'opérateur d'égalité =