PostgreSQL / PostGIS-Raumindex - keine Beschleunigung

15

Ich habe eine räumliche Tabelle in einer PostgreSQL / PostGIS-Datenbank. Jede Zeile repräsentiert ein Polygon. Es hat folgende Form:

+----+--------+
|gid |   way  |
+----+--------+
|241 | 01030..|

Die geometrische Spalte ist "Weg", der die Geometrie für ein Polygon enthält. In WKT heißt es: POLYGON (('....')). Ich führe viele ST_Contains-Abfragen in dieser Tabelle durch, um zu testen, ob zwei Polygone ineinander enthalten sind, z.

Select ST_Contains(a.way, b.way) From table AS a, table AS b Where a.gid = 15 And b.gid = 16

Ich habe mich gefragt, wie ich diese Abfrage beschleunigen kann, und der Tabelle einen räumlichen Index hinzugefügt:

CREATE INDEX table_way_gist ON table USING gist(way);

Aber eigentlich sehe ich keine Beschleunigung. Ich erstelle den Index, nachdem ich die Tabelle mit allen Polygonen gefüllt habe, bevor ich die ST_Contains-Abfragen durchführe. Sollte der Index hinzugefügt werden, bevor eine Tabelle gefüllt wird? Gibt es spezielle Anforderungen an die Tabelle, um mit dem Index zu arbeiten? Die Projektion (srid) des geometrischen Säulenwegs ist auf 900913 eingestellt.

Ich verwende: psql (PostgreSQL) 9.1.4 / POSTGIS = "1.5.3"

MichiMichbeck
quelle

Antworten:

16

Der effizienteste Index für die in Ihrer Frage ausgedrückte Abfrage ist der Index für gid, da er die einzige Spalte ist, die in einem where-Ausdruck angezeigt wird:

 CREATE INDEX table_gid ON table (gid);

Sie können den Listenindex sicher löschen, da er nur Speicherplatz beansprucht und das Einfügen / Aktualisieren / Löschen verlangsamt.

Lange Erklärung

Wie ich bereits sagte, ist der effektivste Index in Ihrem Fall der auf gid, da er es der Datenbank-Engine ermöglicht, Zeilen schneller abzurufen (wobei der Abruf normalerweise der langsamste Teil des Prozesses ist). Danach wird es wahrscheinlich besser sein, das Ergebnis der

  ST_Contains(a.way, b.way)

Unterdrückung ohne Blick auf den Index. Der Grund dafür ist, dass der Abfrageplaner wahrscheinlich einschätzen wird, dass die zusätzlichen Kosten für das Nachschlagen des Hauptindex für beide Spalten im Vergleich zum direkten Nachschlagen der a.way- und b.way- Werte den Aufwand nicht wert sind, da die Gesamtanzahl der nachzuschlagenden Zeilen ist wahrscheinlich sehr klein, besonders wenn der Index eindeutig ist.

Denken Sie als Faustregel daran, dass der Planer wahrscheinlich einen Tabellenscan einem Indexscan für kleine Datensätze vorziehen wird (die Größe der Datensätze wird anhand der Tabellenstatistik geschätzt).

unicoletti
quelle
Das macht mir das Problem klarer. Ich werde es versuchen. Wenn ich also die Abfrage ST_Contains () in die WHERE-Klausel setze, sollte der räumliche Index tatsächlich hilfreich sein? Ich denke, ich muss mein Skript neu organisieren, um ST_Contains in der WHERE-Klausel aufzurufen. Im Moment durchlaufe ich alle Polygone und teste immer zwei davon separat.
MichiMichbeck
?? Sie sind der Meinung, dass ein räumlicher Index die Dinge verlangsamt? Das ist neu für mich, denn wo ich arbeite, haben wir räumliche Indizes für jede einzelne Tabelle und ich frage mich, ob es eine schlechte Praxis ist
Luffydude,
13

Wie unicoletti sagte, würde der Listenindex in der Geometriespalte nur funktionieren, wenn Sie ST_Contains () im WHERE-Ausdruck verwenden.

Wenn Sie beispielsweise alle Polygone kennen möchten, die sich gegenseitig enthalten, können Sie Folgendes verwenden:

SELECT a.gid, b.gid
FROM table AS a, table as b
WHERE a.gid != b.gid and ST_Contains(a.way, b.way)

In diesem Fall sollte der Listenindex abhängig von der Größe Ihrer Tabelle und der Komplexität Ihrer Geometrien eine erhebliche Beschleunigung bewirken, da ST_Contains zunächst die Polygone filtert, indem ihre Begrenzungsrahmen verglichen werden, bevor die vollständigen Geometrien überprüft werden. Eine kleine Erklärung finden Sie im OpenGeo Tutorial .

Alexandre Neto
quelle
Ja, ich verstehe, ich benötige diese Abfrage, um den Indexgrenzentest durchzuführen. Thx Alexandre. (Ich werde Unicoletti als Lösung markieren, da er schnell war und das Problem für mich
behoben