sql >> Base de Datos >  >> RDS >> PostgreSQL

unaccent () que impide el uso del índice en Postgres

Variante INMUTABLE de unaccent()

Para aclarar la información errónea en la respuesta incorrecta actualmente aceptada :
Los índices de expresión solo permiten IMMUTABLE funciones (por razones obvias) y unaccent() es solo STABLE . La solución que sugirió en el comentario también es problemático. Explicación detallada y una solución adecuada por eso :

Dependiendo del contenido de tags->name puede ser útil agregar unaccent() al índice de expresión, pero eso es ortogonal a la pregunta de por qué no se usó el índice:

Problema real/solución

El operador LIKE en su consulta es sutilmente incorrecta (más probable). Tu no desea interpretar 'Weststrasse' como patrón de búsqueda, desea hacer coincidir la cadena (normalizada) tal como está. Reemplazar con = operador, y verá un escaneo de índice (mapa de bits) con su índice actual, independientemente de la volatilidad de la función de unaccent() :

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

¿Por qué?

El operando derecho de LIKE es un patrón . Postgres no puede usar un índice btree simple para la coincidencia de patrones ( se aplican excepciones ). UN LIKE con una cadena simple como patrón (sin caracteres especiales) se puede optimizar con una verificación de igualdad en el índice btree. Pero si hay caracteres especiales en la cadena, this el índice está fuera.

Si hay un IMMUTABLE función a la derecha de LIKE , se puede evaluar inmediatamente y dicha optimización sigue siendo posible. Por documentación sobre Categorías de volatilidad de funciones :

No es posible lo mismo con una función de menor volatilidad (STABLE o VOLATILE ). Es por eso que su "solución" de fingir un IMMUTABLE unaccent() parecía funcionar, pero en realidad es poner lápiz labial en un cerdo.

Para reiterar:

  • Si quieres trabajar con LIKE y patrones, use un trigram index .
  • Si no desea trabajar con LIKE y patrones, use el operador de igualdad =