PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

unaccent() verhindert Indexnutzung in Postgres

IMMUTABLE Variante von unaccent()

Um die Fehlinformationen in der derzeit akzeptierten, falschen Antwort zu klären :
Expression-Indizes erlauben nur IMMUTABLE Funktionen (aus offensichtlichen Gründen) und unaccent() ist nur STABLE . Die Lösung, die Sie im Kommentar vorgeschlagen haben ist auch problematisch. Detaillierte Erklärung und eine richtige Lösung dafür :

Abhängig vom Inhalt von tags->name es kann nützlich sein, unaccent() hinzuzufügen zum Ausdrucksindex, aber das ist orthogonal zu der Frage, warum der Index nicht verwendet wurde:

Eigentliches Problem / Lösung

Der Operator LIKE in Ihrer Abfrage ist subtil falsch (höchstwahrscheinlich). Du nicht Wenn Sie „Weststraße“ als Suchmuster interpretieren möchten, möchten Sie die (normalisierte) Zeichenfolge so abgleichen, wie sie ist. Ersetzen Sie durch = -Operator, und Sie sehen einen (Bitmap-)Index-Scan mit Ihrem aktuellen Index, ungeachtet der Funktionsvolatilität von unaccent() :

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

Warum?

Der rechte Operand von LIKE ist ein Muster . Postgres kann keinen einfachen btree-Index für den Musterabgleich verwenden ( Ausnahmen gelten ). Ein LIKE mit einem einfachen String als Muster (keine Sonderzeichen) kann mit einer Gleichheitsprüfung auf dem btree-Index optimiert werden. Aber wenn der String Sonderzeichen enthält, this Index ist aus.

Wenn es einen IMMUTABLE gibt Funktion rechts von LIKE , kann es sofort ausgewertet werden und die besagte Optimierung ist noch möglich. Per Dokumentation zu Funktionsvolatilitätskategorien :

Dasselbe ist mit einer geringeren Volatilität der Funktion nicht möglich (STABLE oder VOLATILE ). Deshalb Ihre "Lösung", einen IMMUTABLE unaccent() vorzutäuschen schien zu funktionieren, aber es ist wirklich Lippenstift auf ein Schwein.

Um es noch einmal zu wiederholen:

  • Wenn Sie mit LIKE arbeiten möchten und Muster verwenden Sie einen Trigrammindex .
  • Wenn Sie nicht mit LIKE arbeiten möchten und Muster verwenden Sie den Gleichheitsoperator =