Ich habe 2 Sätze von Punkten in 2 separaten Tabellen. Table_a hat 100.000 Punkte und table_b hat 300.000 Punkte. Wenn ich versuche, die nächsten Punkte in Bezug zu finden, finde ich einen beliebigen Punkt aus table_b, der sich innerhalb von 50 Metern von tabla_a befindet. Nachdem Sie die Fallspalte berechnet haben, gruppieren Sie sie nach der Spalte table_a a_id und geben den höchsten Wert zurück.
Ich habe eine folgende Abfrage geschrieben, die diese Kriterien erfüllt
SELECT DISTINCT ON (a_id) *
FROM (
SELECT
table_b.b_id,
table_b.height - st_3ddistance(table_b.geom, table_a.geom) fall,
table_b.geom,
table_a.a_id
FROM table_a
INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;
Ich habe 3D-Geometrieindizes hinzugefügt:
CREATE INDEX table_a_geom ON table_a USING GIST (geom gist_geometry_ops_nd);
CREATE INDEX table_b_geom ON table_b USING GIST (geom gist_geometry_ops_nd);
Mein Problem ist jedoch, dass ich keine Abfrage machen kann, um sie zu verwenden. Der Abfrageplaner wählt weiterhin einen langsamen Sequenzscan. Ich führe einen Test durch, bei dem _st_3ddwithin mit st_3ddwithin , <<- >> <50 geändert wird , wobei 50 m Puffer erstellt und st_3ddistance <50 geschnitten werden , aber jedes Mal, wenn der Planer den Sequenzscan wählt. Gibt es eine Möglichkeit, Indizes mit höherer Leistung zu verwenden oder die Abfrage so zu ändern, dass Indizes verwendet werden?
Mein Abfrageplan:
Unique (cost=10462593.70..10473018.43 rows=1 width=144)
-> Sort (cost=10462593.70..10467806.06 rows=2084945 width=144)
Sort Key: table_a.nmbayuid, ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom))) DESC
-> Nested Loop (cost=0.00..10243762.28 rows=2084945 width=144)
Join Filter: (_st_dwithin(table_a.geom, table_b.geomgr, '50'::double precision) AND ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom)) >= '0'::double precision))
-> Seq Scan on table_b (cost=0.00..1459.47 rows=47147 width=96)
-> Materialize (cost=0.00..10.97 rows=398 width=56)
-> Seq Scan on table_a (cost=0.00..8.98 rows=398 width=56)
quelle
_ST
sind interne Funktionen, die von PostGIS nach dem Filtern mit einem Index aufgerufen werden. Wenn Sie sie direkt aufrufen, wird der Index nicht verwendet.Antworten:
Erstens führt, wie in den Kommentaren erwähnt, der führende Unterstrich vor der ST-Funktion, dh _ST_3DWithin, dazu, dass der Index nicht verwendet wird. Ich kann dies in letzter Zeit nicht erwähnen, aber in älteren Dokumenten heißt es, wenn Sie nach z. B. _ST_Intersects suchen:
BEARBEITEN: Wie von @dbaston in den Kommentaren klargestellt, sind die Funktionen mit dem führenden Unterstrich interne Funktionen, die den Index beim Aufruf nicht verwenden, und dies ist weiterhin der Fall (obwohl es in den Dokumenten schwer zu finden ist).
Ihre Abfrage könnte möglicherweise von der LATERAL JOIN-Syntax profitieren, die sich gut für Probleme mit k nächsten Nachbarn (kNN) wie diesem eignet.
Auf diese Weise können Sie die nächsten k Geometrien von Tabelle a (in diesem Fall 1 aufgrund von LIMIT 1) bis Tabelle b finden, geordnet nach dem 3D-Abstand zwischen ihnen. Es wird mit LEFT JOIN geschrieben, da es denkbar ist, dass in Tabelle a einige Geometrien vorhanden sind, die nicht innerhalb von 50 Metern von Tabelle b liegen.
Mit den seitlichen Abfragen können Sie auf Spalten aus der vorherigen FROM-Klausel verweisen. Dies macht sie leistungsfähiger als Standard-Unterabfragen (siehe Dokumente) .
Ich kann dies nicht mit Ihren Daten testen, aber wenn ich ähnliche Abfragen ausgeführt habe, zeigt die EXPLAIN-Anweisung die ordnungsgemäße Verwendung des Index an.
quelle
Dieser Link zur PostGIS-Dokumentation empfiehlt die folgenden Schritte, um sicherzustellen, dass Indizes und Abfrageplaner optimiert sind:
Stellen Sie sicher, dass Statistiken über die Anzahl und Verteilung der Werte in einer Tabelle gesammelt werden, um dem Abfrageplaner bessere Informationen für Entscheidungen zur Indexnutzung zu liefern. VACUUM ANALYZE berechnet beide.
Wenn das Staubsaugen nicht hilft, können Sie den Planer vorübergehend zwingen, die Indexinformationen zu verwenden, indem Sie den Wert enable_seqscan auf off setzen. Befehl. Auf diese Weise können Sie überprüfen, ob der Planer überhaupt in der Lage ist, einen indexbeschleunigten Abfrageplan für Ihre Abfrage zu generieren. Sie sollten diesen Befehl nur zum Debuggen verwenden: Im Allgemeinen weiß der Planer besser als Sie, wann Indizes verwendet werden sollen. Vergessen Sie nach dem Ausführen Ihrer Abfrage nicht, ENABLE_SEQSCAN wieder zu aktivieren, damit andere Abfragen den Planer wie gewohnt verwenden.
Wenn enable_seqscan auf off gesetzt ist; Wenn Ihre Abfrage ausgeführt wird, ist Ihr Postgres wahrscheinlich nicht auf Ihre Hardware abgestimmt. Wenn Sie feststellen, dass der Planer hinsichtlich der Kosten für sequentielle und Index-Scans falsch ist, reduzieren Sie den Wert von random_page_cost in postgresql.conf oder setzen Sie random_page_cost auf 1.1;. Der Standardwert für den Parameter ist 4, versuchen Sie, ihn auf 1 (auf SSD) oder 2 (auf schnellen Magnetplatten) einzustellen. Durch Verringern des Werts ist der Planer eher geneigt, Index-Scans zu verwenden.
Wenn enable_seqscan auf off gesetzt ist; hilft Ihrer Abfrage nicht, es kann vorkommen, dass Sie eine Konstruktion verwenden, die Postgres noch nicht entwirren kann. Eine Unterabfrage mit Inline-Auswahl ist ein Beispiel - Sie müssen sie in den Formularplaner umschreiben, um beispielsweise einen LATERAL JOIN zu optimieren.
Versuchen Sie also zuerst die Schritte 1 bis 3, bevor Sie Ihre Abfrage neu schreiben, um die Indizes zu verwenden. Wenn dies nicht funktioniert, können Sie versuchen, die Abfrage zu ändern.
Ich glaube (nach bestem Wissen und Gewissen, SQL zu erstellen, ohne den Code auszuführen), dass die folgende Abfrage identische Ergebnisse für Ihre zurückgibt, weiß aber nicht, ob sie effizienter ist.
quelle
Wenn Sie Postgres 10 (oder neuer) verwenden, würde ich dringend empfehlen, Ihre Daten in parallele Tabellen zu laden.
Sie müssen wahrscheinlich Zeit damit verbringen, es zu optimieren (Datenpartitionierung und Anzahl der Mitarbeiter), aber ich denke, die Mühe lohnt sich. Theoretisch ist KNN stark parallelisierbar und erreicht konstante Zeitkomplexitäten, sogar O (1), wenn die Anzahl der Arbeiter gleich der Anzahl der Elemente ist, für die eine KNN-Operation berechnet wird.
Einige praktische Bezug auf die Daten geladen werden und die Durchführung der Abfragen werden zur Verfügung gestellt hier . Er bietet einige Details über Plan tunning (um mehr Arbeiter zu zwingen, werden actioned) hier . Es ist wichtig zu bemerken, dass parallele Skripte viel Aufgabenkoordination erfordern, so dass die extreme theoretische Grenze für die Bereitstellung der extremsten Parallelisierung in der Praxis aufgrund der Vernetzung und anderer Systemdesignmerkmale nicht gilt.
quelle