sql >> Database >  >> RDS >> PostgreSQL

LATERAL JOIN gebruikt geen trigram-index

Waarom?

De query kan de index op principal niet gebruiken. Je hebt een index nodig op de tabel locations , maar degene die je hebt staat op de tafel addresses .

U kunt mijn claim verifiëren door het volgende in te stellen:

SET enable_seqscan = off;

(Alleen in uw sessie en alleen voor debuggen. Gebruik het nooit in productie.) Het is niet alsof de index duurder zou zijn dan een sequentiële scan, Postgres kan het gewoon helemaal niet gebruiken voor uw zoekopdracht .

Terzijde:[INNER] JOIN ... ON true is gewoon een ongemakkelijke manier om CROSS JOIN ... . te zeggen

Waarom wordt de index gebruikt na het verwijderen van ORDER en LIMIT ?

Omdat Postgres deze eenvoudige vorm kan herschrijven tot:

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

U ziet exact hetzelfde queryplan. (Tenminste dat doe ik in mijn tests op Postgres 9.5.)

Oplossing

Je hebt een index nodig op locations.postalcode . En tijdens het gebruik van LIKE of ILIKE je zou ook de geïndexeerde uitdrukking (postalcode ) naar links kant van de bediener. ILIKE wordt geïmplementeerd met de operator ~~* en deze operator heeft geen COMMUTATOR (een logische noodzaak), dus het is niet mogelijk om operanden om te draaien. Gedetailleerde uitleg in deze gerelateerde antwoorden:

Een oplossing is om de trigram-overeenkomstoperator % of het omgekeerde, de afstandsoperator <-> in een dichtstbijzijnde buur query in plaats daarvan (elk is een commutator voor zichzelf, dus operanden kunnen vrij van plaats wisselen):

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

Vind de meest gelijkende postalcode voor elk address , en controleer dan of die postalcode komt eigenlijk volledig overeen.

Op deze manier een langere postalcode krijgt automatisch de voorkeur omdat het meer op elkaar lijkt (kleinere afstand) dan een kortere postalcode dat komt ook overeen.

Er blijft een beetje onzekerheid. Afhankelijk van mogelijke postcodes, kunnen er valse positieven zijn als gevolg van overeenkomende trigrammen in andere delen van de tekenreeks. Er is niet genoeg informatie in de vraag om meer te zeggen.

Hier , [INNER] JOIN in plaats van CROSS JOIN is logisch, aangezien we een daadwerkelijke deelnamevoorwaarde toevoegen.

De handleiding:

Dus:

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


  1. Paginering met MySQL LIMIT, OFFSET

  2. Hoe weet ik of mijn PostgreSQL-back-up goed is?

  3. Python Unicode-coderingsprobleem

  4. Foutmelding tijdens het uitvoeren van Stroredprocedure