Wie kann ein Leistungsproblem in PostGIS ST_Intersects behoben werden?

9

Ich bin ein Neuling in Postgis und habe ein Problem mit der Abfrageleistung.

Dies ist meine Frage:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

und das Problem ist, dass mein Multipolygon SEHR große Polygone enthält (600 Seiten lang in Word Doc!) und die Ausführung mehr als 2 Stunden gedauert hat!

Gibt es eine Möglichkeit, meine Abfrage zu optimieren oder eine andere zu verwenden?

Bitte Ihre Hilfe wird sehr geschätzt!

Sara
quelle

Antworten:

8

Was Sie tun sollten, ist, Ihr großes Multipolygon als einzelne Polygone (mit ST_Dump) in eine Tabelle einzufügen und einen Index darauf zu setzen. So etwas wie:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

Das sollte aus mehreren Gründen viel schneller sein.

Nicklas Avén
quelle
Danke Nicklas für diese tolle Antwort. Es tut mir leid, dass ich nicht erwähnt habe, dass ich mehr als ein Polygon habe und diese bereits in einer Tabelle mit Index gespeichert sind. Aber ich sollte die Geomdaten direkt bereitstellen, wäre schneller. Ich versuche es jedoch so, wie Sie es vorschlagen, aber es dauert immer noch sehr lange! irgendeinen anderen Vorschlag?
Sara
@Sara . Ok, Sie haben also versucht, die Multigeoemtries in einzelne Geometrien aufzuteilen, wie ich es mit ST_Dump vorschlage?
Nicklas Avén
Über wie viele Benutzerpositionen sprechen wir? Wie viele große Polygone? Was bekommen Sie von SELECT ST_npoints (geom) von big_polygons_table?
Nicklas Avén
Tut mir leid, mein Schlechtes, lassen Sie mich mehr über meine Tabellen erklären, um es für Sie klarer zu machen: Ich habe Tabelle1, die eine Geom-Spalte mit etwa 230 Zeilen enthält, und in jeder Zeile befindet sich ein Multipolygon (sie repräsentieren Länder, sodass sie unterschiedlich groß sind). , und haben Index in the_geom col. Tabelle 2 enthält Positionsspalte (Punkte), Zeitstempel, Benutzer-ID und ID (pk) sowie 3 Indizes, die mit (Position, Zeitstempel, Benutzer-ID) erstellt wurden. Diese Tabelle ist sehr groß, etwa 103496003 Zeilen. Die maximale Anzahl von ST_npoints beträgt 1440430 und die minimale Anzahl ist 16. Es tut mir leid, wenn ich Sie verwirrt habe, aber ich brauche wirklich Ihre Hilfe! Vielen Dank
Sara
2

Es kommt darauf an, welche Art von Qualität - Präzision Sie benötigen. Sie können die Polygone natürlich vereinfachen, indem Sie Folgendes verwenden: http://postgis.net/docs/ST_Simplify.html

Während der Entwicklung meiner GIS-Anwendung habe ich häufig überlegt, wie Daten am besten minimiert werden können. Z.B. Wählen Sie beispielsweise die Polygone im Begrenzungsfeld vor. - Je nach Zoomstufe benötigen Sie keine ultrapräzisen Ergebnisse (st_simplify) usw.

Hoffe das hat dir ein bisschen geholfen!

Styp
quelle
Danke Martin für deine schnelle Antwort. Mein Problem ist, dass das Ergebnis sehr genau sein muss, daher denke ich, dass diese Funktion mir hier nicht helfen wird! aber danke für den Vorschlag
Sara
0

Abhängig von Ihrer Postgres- und / oder SQL-Expertise haben Sie mehrere Möglichkeiten:

  1. Analysieren Sie die Abfrage mit dem Befehl EXPLAIN , um herauszufinden, ob Sie auf einen bestimmten Engpass stoßen . Warnung: Manchmal ist die Ausgabe von EXPLAIN schwer zu verstehen

  2. Wenn Sie erwarten, dass die meisten oder ein erheblicher Teil der Geometrien in Tabelle 1 das Multipolygon NICHT schneiden, können Sie versuchen, eine vorläufige Bedingung auf ein einfacheres Polygon anzuwenden (dh indem Sie das Multiploygon in kleinere Teile zerlegen) und dann den schwereren Multipolygonschnitt nur auf ausführen diese Ergebnisse. Ein Beispiel finden Sie weiter unten.

  3. wenn und nur wenn CPU der Engpass (dh der Server stecken Computing Kreuzungen) I ist dumpf schlage vor , Sie bekommen einen größeren, schnelleren, leistungsfähigeren CPU oder mieten eine einmalige High-CPU Instanz aus Amazons EC2 und zerstören es , wenn du bist getan

Beispielabfrage für Punkt 2:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

Um die Leistung zu verbessern, können Sie auch die Unterauswahl st1 vorübergehend als Tabelle materialisieren , damit Sie sie indizieren können.

@Nicklas weist in den Kommentaren zu Recht darauf hin, dass ein Beispiel für Vorschlag 2 nicht helfen sollte. Er hat recht, aber ich denke, ich habe (teilweise) auch recht.

Tatsächlich scheint es, dass eine sehr ähnliche Frage erst letzten November auf der Postgis ML gestellt (und beantwortet) wurde:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

und es stellt sich heraus, dass der Vorschlag darin besteht, das Polygon tatsächlich aufzubrechen, damit der Index am effektivsten falsche Schnittpunkte herausfiltern kann, die andernfalls durch eine einfache Grenzprüfung ausgelöst würden.

Unicoletti
quelle
Vorschlag 2 sollte nicht helfen, da der Index genau das tut. Dieses Konstrukt wird also wieder dasselbe tun.
Nicklas Avén
@ NicklasAvén Sie haben Recht, ich habe die Antwort geändert
unicoletti
0

Verwenden von ST_SubDivide()

Für Version 2.2 von Postgis können Sie verwenden ST_SubDivide.

ST_Subdivide - Gibt eine Menge Geometrie zurück, bei der keine Geometrie in der Menge mehr als die angegebene Anzahl von Scheitelpunkten hat.

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

Sie können auch

  • Verwenden Sie eine temporäre Tabelle
  • ein Index

Hier verwenden wir ST_SubDivide, um das Polygon in Subpolygone mit 10 oder weniger Eckpunkten zu zerlegen.

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

Dann

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

Tun Sie dies nicht, da dies zu Rundungsfehlern führt

Allgemeine Abstimmung

Lesen Sie auch den Abschnitt Leistungstipps in den Dokumenten. Stellen Sie sicher, dass Sie richtig eingestellt sind. Erwägen Sie eine Erhöhung max_parallel_workers_per_gather, um die Parallelisierung zu nutzen (derzeit standardmäßig deaktiviert).

Evan Carroll
quelle