sql >> Database teknologi >  >> RDS >> PostgreSQL

LATERAL JOIN bruger ikke trigramindeks

Hvorfor?

Forespørgslen kan ikke bruge indekset på principal. Du skal bruge et indeks på tabellen placeringer , men den du har er på tabellen adresser .

Du kan bekræfte mit krav ved at indstille:

SET enable_seqscan = off;

(Kun i din session og kun til fejlfinding. Brug det aldrig i produktionen.) Det er ikke sådan, at indekset ville være dyrere end en sekventiel scanning, der er bare ingen måde for Postgres at bruge det til din forespørgsel overhovedet .

Til side:[INNER] JOIN ... ON true er bare en akavet måde at sige CROSS JOIN ...

Hvorfor bruges indekset efter fjernelse af ORDER og LIMIT ?

Fordi Postgres kan omskrive denne simple formular til:

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

Du vil se nøjagtig den samme forespørgselsplan. (Det gør jeg i hvert fald i mine test på Postgres 9.5.)

Løsning

Du skal bruge et indeks på locations.postalcode . Og mens du bruger LIKE eller ILIKE du skal også medbringe det indekserede udtryk (postalcode ) til venstre operatørens side. ILIKE er implementeret med operatøren ~~* og denne operatør har ingen COMMUTATOR (en logisk nødvendighed), så det er ikke muligt at vende operander rundt. Detaljeret forklaring i disse relaterede svar:

En løsning er at bruge trigram-lighedsoperatoren % eller dets omvendte, afstandsoperatøren <-> i en nærmeste nabo forespørgsel i stedet (hver er kommutator for sig selv, så operander kan skifte plads frit):

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

Find det mest lignende postnummer for hver adresse , og kontroller derefter, om det postnummer faktisk matcher fuldt ud.

På denne måde et længere postnummer vil blive foretrukket automatisk, da det er mere ens (mindre afstand) end et kortere postnummer der også matcher.

Der er en smule usikkerhed tilbage. Afhængigt af mulige postnumre kan der være falske positiver på grund af matchende trigrammer i andre dele af strengen. Der er ikke nok information i spørgsmålet til at sige mere.

Her , [INDRE] JOIN i stedet for CROSS JOIN giver mening, da vi tilføjer en faktisk forbindelsesbetingelse.

Manualen:

Så:

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


  1. Hvordan tvinges pascal-sag med Oracles Entity Framework-understøttelse?

  2. Binding af forespørgselsparametre efter navn med ODP.NET

  3. Indsæt flere poster i oracle

  4. MySQL LEFT JOIN-forespørgsel med WHERE-klausul