sql >> Databasteknik >  >> RDS >> PostgreSQL

LATERAL JOIN använder inte trigramindex

Varför?

Frågan kan inte använda indexet på principal. Du skulle behöva ett index på tabellen platser , men den du har finns i tabellen adresser .

Du kan verifiera mitt anspråk genom att ställa in:

SET enable_seqscan = off;

(Endast i din session och endast för felsökning. Använd det aldrig i produktionen.) Det är inte som att indexet skulle vara dyrare än en sekventiell skanning, det finns helt enkelt inget sätt för Postgres att använda det för din fråga överhuvudtaget .

Bortsett från:[INNER] JOIN ... ON true är bara ett besvärligt sätt att säga CROSS JOIN ...

Varför används indexet efter att ORDER tagits bort och LIMIT ?

Eftersom Postgres kan skriva om detta enkla formulär till:

SELECT *
FROM   addresses a
JOIN   locations l ON a.address ILIKE '%' || l.postalcode || '%';

Du kommer att se exakt samma frågeplan. (Åtminstone gör jag det i mina tester på Postgres 9.5.)

Lösning

Du behöver ett index på locations.postalcode . Och medan du använder LIKE eller ILIKE du skulle också behöva ta med det indexerade uttrycket (postalcode ) till vänster operatörens sida. ILIKE implementeras med operatorn ~~* och den här operatören har ingen COMMUTATOR (en logisk nödvändighet), så det är inte möjligt att vända på operander. Detaljerad förklaring i dessa relaterade svar:

En lösning är att använda trigramlikhetsoperatorn % eller dess invers, distansoperatören <-> i en närmaste granne fråga istället (var och en är kommutator för sig själv, så operander kan byta plats fritt):

SELECT *
FROM   addresses a
JOIN   LATERAL (
   SELECT *
   FROM   locations
   ORDER  BY postalcode <-> a.address
   LIMIT  1
   ) l ON address ILIKE '%' || postalcode || '%';

Hitta det mest liknande postnumret för varje adress , och kontrollera sedan om det postnumret matchar faktiskt helt.

På så sätt ett längre postnummer kommer att föredras automatiskt eftersom det är mer likt (mindre avstånd) än ett kortare postnummer som också matchar.

Lite osäkerhet kvarstår. Beroende på möjliga postnummer kan det finnas falska positiva resultat på grund av matchande trigram i andra delar av strängen. Det finns inte tillräckligt med information i frågan för att säga mer.

Här , [INNER] JOIN istället för CROSS JOIN vettigt, eftersom vi lägger till ett faktiskt sammanfogningsvillkor.

Manualen:

Så:

CREATE INDEX locations_postalcode_trgm_gist_idx ON locations
USING gist (postalcode gist_trgm_ops);


  1. RAWTOHEX() Funktion i Oracle

  2. UTF8-tecken visas inte korrekt med datatabeller och yadcf

  3. Hur kan jag skriva om min PHP &MySQL för att gruppera min HTML-lista efter lika kolumnvärden?

  4. Främmande nycklar som hänvisar till andra främmande nycklar i PostgreSQL