PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

ŁĄCZENIE BOCZNE nie używa indeksu trygramu

Dlaczego?

Kwerenda nie może używać indeksu w jednostce głównej. Potrzebujesz indeksu w tabeli lokalizacje , ale ten, który masz, jest w tabeli adresy .

Możesz zweryfikować moje roszczenie, ustawiając:

SET enable_seqscan = off;

(Tylko w Twojej sesji i tylko do debugowania. Nigdy nie używaj go w środowisku produkcyjnym.) Indeks nie byłby droższy niż skanowanie sekwencyjne, po prostu Postgres nie ma możliwości użycia go w zapytaniu .

Na bok:[INNER] JOIN ... ON true to tylko niezręczny sposób powiedzenia CROSS JOIN ...

Dlaczego indeks jest używany po usunięciu ORDER? i LIMIT ?

Ponieważ Postgres może przepisać ten prosty formularz, aby:

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

Zobaczysz dokładnie ten sam plan zapytań. (Przynajmniej robię to w moich testach na Postgresie 9.5.)

Rozwiązanie

Potrzebujesz indeksu na locations.postalcode . I podczas korzystania z LIKE lub ILIKE musisz również przynieść zindeksowane wyrażenie (kod pocztowy ) po po lewej stronie operatora. ILIKE jest zaimplementowany z operatorem ~~* a ten operator nie ma KOMUTATORA (logiczna konieczność), więc nie można odwrócić operandów. Szczegółowe wyjaśnienie w tych powiązanych odpowiedziach:

Rozwiązaniem jest użycie operatora podobieństwa trygramów % lub jego odwrotność, operator odległości <-> u najbliższego sąsiada zamiast tego zapytanie (każdy jest komutatorem sam dla siebie, więc operandy mogą swobodnie zmieniać miejsca):

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

Znajdź najbardziej podobny kod pocztowy dla każdego adresu , a następnie sprawdź, czy ten kod pocztowy faktycznie pasuje w pełni.

W ten sposób dłuższy kod pocztowy będzie preferowany automatycznie, ponieważ jest bardziej podobny (mniejsza odległość) niż krótszy kod pocztowy to również pasuje.

Pozostaje trochę niepewności. W zależności od możliwych kodów pocztowych mogą wystąpić fałszywe alarmy z powodu pasujących trygramów w innych częściach ciągu. W pytaniu nie ma wystarczających informacji, aby powiedzieć więcej.

Tu , [INNER] JOIN zamiast CROSS JOIN ma sens, ponieważ dodajemy rzeczywisty warunek dołączenia.

Podręcznik:

A więc:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Atomic UPDATE .. SELECT w Postgres

  2. postgresql - uzyskaj listę różnic w kolumnach między 2 tabelami

  3. Czy tworzenie rozszerzenia działa w trybie pojedynczego użytkownika w postgresie?

  4. Czy specyfikacja JDBC zapobiega '?' przed użyciem jako operator (poza cudzysłowami)?

  5. Konwertuj szesnastkę w reprezentacji tekstowej na liczbę dziesiętną