sql >> Databáze >  >> RDS >> PostgreSQL

LATERAL JOIN nepoužívá index trigramů

Proč?

Dotaz nemůže použít index na principu. Budete potřebovat index v tabulce locations , ale ten, který máte, je v tabulce addresses .

Můj nárok můžete ověřit nastavením:

SET enable_seqscan = off;

(Pouze ve vaší relaci a pouze pro ladění. Nikdy to nepoužívejte v produkci.) Není to tak, že by index byl dražší než sekvenční skenování, prostě neexistuje žádný způsob, jak ho Postgres pro váš dotaz vůbec použít .

Stranou:[INNER] JOIN ... ON true je jen nepříjemný způsob, jak říct CROSS JOIN ...

Proč se po odstranění ORDER používá index a LIMIT ?

Protože Postgres umí tento jednoduchý formulář přepsat na:

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

Uvidíte přesně stejný plán dotazů. (Aspoň já to dělám ve svých testech na Postgres 9.5.)

Řešení

Potřebujete index na locations.postalcode . A při používání ILIKE nebo ILIKE budete také muset přinést indexovaný výraz (postalcode ) doleva straně operátora. ILIKE je implementován operátorem ~~* a tento operátor nemá COMMUTATOR (logická nutnost), takže není možné operandy obracet. Podrobné vysvětlení v těchto souvisejících odpovědích:

Řešením je použít trigramový operátor podobnosti % nebo jeho inverzní, operátor vzdálenosti <-> u nejbližšího souseda dotaz (každý je komutátor sám pro sebe, takže operandy mohou libovolně přepínat místa):

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

Najděte nejpodobnější postalcode pro každou address a poté zkontrolujte, zda postalcode ve skutečnosti plně odpovídá.

Tímto způsobem delší postalcode bude preferováno automaticky, protože je podobnější (menší vzdálenost) než kratší postalcode to také odpovídá.

Zůstává trochu nejistoty. V závislosti na možných poštovních směrovacích číslech se mohou vyskytnout falešné poplachy kvůli odpovídajícím trigramům v jiných částech řetězce. V otázce není dostatek informací, abych řekl více.

Zde , [INNER] JOIN místo CROSS JOIN dává smysl, protože přidáváme skutečnou podmínku spojení.

Příručka:

Takže:

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


  1. Ladění uložené procedury v SQL Server 2008

  2. Pružinová data JPA pouze jeden složený klíč je problém s automatickým zvýšením

  3. SQL:Co je lepší bit nebo znak (1)

  4. Login-Authentication do vzdálené mysql databáze