sql >> Databasteknik >  >> RDS >> PostgreSQL

unaccent() förhindrar indexanvändning i Postgres

IMMUTABAR variant av unaccent()

För att förtydliga den felaktiga informationen i det för närvarande accepterade, felaktiga svaret :
Uttrycksindex tillåter endast IMMUTABLE funktioner (av uppenbara skäl) och unaccent() är bara STABLE . lösningen som du föreslog i kommentaren är också problematiskt. Detaljerad förklaring och en rätt lösning för det :

Beroende på innehållet i tags->name det kan vara användbart att lägga till unaccent() till uttrycksindexet, men det är ortogonalt till frågan varför indexet inte användes:

Faktiskt problem/lösning

Operatören LIKE i din fråga är subtilt fel (mest troligt). Det gör du inte Om du vill tolka 'Weststrasse' som sökmönster, vill du matcha den (normaliserade) strängen som den är. Ersätt med = operatorn, och du kommer att se en (bitmapp) indexskanning med ditt nuvarande index, oavsett av funktionsvolatiliteten för unaccent() :

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

Varför?

Den högra operanden av LIKE är ett mönster . Postgres kan inte använda ett vanligt btree-index för mönstermatchning ( undantag gäller ). En LIKE med en vanlig sträng som mönster (inga specialtecken) kan optimeras med en likhetskontroll på btree-indexet. Men om det finns specialtecken i strängen, detta index är ute.

Om det finns en IMMUTABLE funktion till höger om LIKE , kan den utvärderas omedelbart och nämnda optimering är fortfarande möjlig. Enligt dokumentation om Funktionsvolatilitetskategorier :

Detsamma är inte möjligt med en mindre funktionsvolatilitet (STABLE eller VOLATILE ). Det är därför din "lösning" att fejka en IMMUTABLE unaccent() verkade fungera, men det är verkligen att sätta läppstift på en gris.

För att upprepa:

  • Om du vill arbeta med LIKE och mönster, använd ett trigramindex .
  • Om du inte vill arbeta med LIKE och mönster, använd likhetsoperatorn =



  1. ORA-01438:värde större än specificerad precision tillåter denna kolumn - Hur får jag fram vilken kolumn den syftar på?

  2. SQLite Insert

  3. Ordinal Not Found när du kör Diesel CLI-verktyget

  4. Få senast infogade ID från MySQL i Yii