LATERAL JOIN verwendet keinen Trigramm-Index

8

Ich möchte einige grundlegende Geokodierung von Adressen mit Postgres durchführen. Ich habe eine Adresstabelle, die ungefähr 1 Million rohe Adressenstrings hat:

%Vor%

Ich habe auch eine Tabelle mit Standortdaten:

%Vor%

Die meisten Adress-Strings enthalten Postleitzahlen, also war mein erster Versuch, einen Like und einen lateralen Join zu machen:

%Vor%

Das ergab das erwartete Ergebnis, aber es war langsam. Hier ist der Abfrageplan:

%Vor%

Ich habe versucht, einen GIST-Trigramm-Index zur Adressspalte hinzuzufügen, wie in Ссылка erwähnt, aber der Abfrageplan für die obige Abfrage verwendet es nicht, und der Abfrageplan unverändert.

%Vor%

Ich muss die Reihenfolge entfernen und in der Querverknüpfungsabfrage für den Index, der verwendet werden soll, begrenzen, was mir nicht die Ergebnisse bringt, die ich möchte. Hier ist der Abfrageplan für die Abfrage ohne ORDER oder LIMIT :

%Vor%

Gibt es etwas, was ich tun kann, um die Abfrage den Index zu verwenden, oder gibt es eine bessere Möglichkeit, diese Abfrage neu zu schreiben?

    
Ben Dowling 17.05.2016, 04:25
quelle

3 Antworten

4

Warum?

Die Abfrage kann den Index für Principal nicht verwenden. Sie würden einen Index für die Tabelle locations benötigen, aber den, den Sie haben, befindet sich in der Tabelle addresses .

Sie können meinen Anspruch überprüfen, indem Sie Folgendes festlegen:

%Vor%

(Nur in Ihrer Sitzung und nur zum Debuggen. Verwenden Sie das Programm nie in der Produktion.) Es ist nicht so, dass der Index teurer wäre als ein sequenzieller Scan. Postgres kann sie einfach nicht für Ihre Abfrage verwenden überhaupt .

Beiseite: [INNER] JOIN ... ON true ist nur eine unbeholfene Art, CROSS JOIN ...

zu sagen

Warum wird der Index nach dem Entfernen von ORDER und LIMIT ?

verwendet?

Weil Postgres dieses einfache Formular in folgendes umschreiben kann:

%Vor%

Sie sehen genau den gleichen Abfrageplan. (Zumindest mache ich bei meinen Tests auf Postgres 9.5.)

Lösung

Sie benötigen einen Index für locations.postalcode . Und bei der Verwendung von LIKE oder ILIKE müssten Sie auch den indizierten Ausdruck ( postalcode ) auf die linke Seite des Operators bringen. ILIKE wird mit dem Operator ~~* implementiert und dieser Operator hat keine COMMUTATOR (eine logische Notwendigkeit), so dass es nicht möglich ist, Operanden umzukehren. Detaillierte Erklärung in diesen verwandten Antworten:

Eine Lösung ist die Verwendung des Trigrammähnlichkeitsoperators % oder umgekehrt, der Entfernungsoperator <-> in einer nearest neighbor -Abfrage (jeder ist Kommutator für sich selbst, so dass Operanden die Plätze frei wechseln können):

%Vor%

Finde die ähnlichste postalcode für jede address und überprüfe dann, ob diese postalcode tatsächlich vollständig übereinstimmt.

Auf diese Weise wird ein längerer postalcode automatisch bevorzugt, da er ähnlicher ist (kleinerer Abstand) als ein kürzerer postalcode , der ebenfalls übereinstimmt.

Ein bisschen Unsicherheit bleibt. Abhängig von möglichen Postleitzahlen könnte es falsche Übereinstimmungen aufgrund übereinstimmender Trigramme in anderen Teilen der Kette geben. Es gibt nicht genug Informationen in der Frage, um mehr zu sagen.

Hier ist [INNER] JOIN anstelle von CROSS JOIN sinnvoll, da wir eine tatsächliche Join-Bedingung hinzufügen.

Das Handbuch:

  

Dies kann sehr effizient durch GiST-Indizes, aber nicht durch GIN-Indizes implementiert werden.

Also:

%Vor%     
Erwin Brandstetter 21.05.2016, 14:51
quelle
2

Es ist weit hergeholt, aber wie funktioniert die folgende Alternative?

%Vor%     
quelle
2

Es kann funktionieren, wenn Sie die seitliche Verbindung von innen nach außen drehen. Aber selbst dann könnte es immer noch sehr langsam sein

%Vor%

Der Nachteil ist, dass Sie Paging nur für Postleitzahlen und nicht für Adressen implementieren können.

    
Jakub Kania 20.05.2016 20:30
quelle