Welche Funktion zum Erstellen eines POINT in PostGIS?

30

Wann entscheiden Sie sich bei der Definition eines Punktes in PostGIS, welchen der folgenden Punkte zu verwenden?

  • ST_SetSRID(ST_MakePoint(lon,lat),4326)
  • ST_SetSRID(ST_Point(long,lat),4326)
  • ST_SetSRID(ST_GeomFromText('POINT(lon lat)',4326)
  • ST_GeomFromEWKT('SRID=4326;POINT(lon lat)')

Wenn es sich im Wesentlichen um einen Leistungsunterschied handelt, welcher ist der schnellste?

Nyxynyx
quelle
Schauen Sie sich diese Antwort an: gis.stackexchange.com/a/285017/6052
Evan Carroll

Antworten:

26

Ich vermute, dass dies ST_MakePointam schnellsten ist, aber dies ist einfach genug, um mit 100.000 zufälligen Punkten einen Benchmark zu erstellen.

\timing

WITH test AS (
  SELECT <POINT CONSTRUCTOR METHOD>
  FROM generate_series(1,100000)
)
SELECT count(*) FROM test;

Und hier sind einige Ergebnisse mit PostGIS 2.1 (trunk) unter PostgreSQL 9.1, x64 Debian. Ich habe sie einige Male gemacht, um einen ungefähren Durchschnitt zu erhalten. Hier sind die <POINT CONSTRUCTOR METHOD>in der Reihenfolge vom schnellsten zum langsamsten:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • durchschnittlich 160 ms
    • bei weitem am schnellsten und bewahrt doppelte Punktgenauigkeit (verlustfrei)
    • Der einfachste Weg, eine parametrisierte Abfrage mit numerischen Koordinatendaten durchzuführen
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • durchschnittliche 760 ms
    • Wenn die Zahl in Text umgewandelt wird, wird die Zeichenfolge langsam zusammengesetzt, und PostGIS muss sie analysieren, um die Zahlen zu finden
    • verlustbehaftet, aufgrund von Zahlen -> Text -> Zahlenumwandlungen
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • durchschnittlich 810 ms
    • am langsamsten, nicht sicher, warum es langsamer ist als ST_GeomFromText

Zuletzt eine kleine Fußnote zum Unterschied zwischen verlustfreien / verlustbehafteten Konvertierungen mit den oben genannten Methoden. Erhält ST_MakePointnur die binären Gleitkomma-Präzisionsdaten, und die Textkonvertierungen kürzen einen sehr kleinen Teil der Daten ab. Obwohl die beiden Punkte möglicherweise binäre Unterschiede aufweisen (siehe WKB), sollten sie räumlich immer gleich sein. Die Abstandsunterschiede sind im Wesentlichen das Maschinen-Epsilon für doppelte Präzision .

SELECT
  (geom_text = geom_binary) AS spatially_equal,
  (geom_text::text = geom_binary::text) AS binary_equal,
  (ST_AsText(geom_text) = ST_AsText(geom_binary)) AS wkt_equal,
  ST_Distance(geom_text, geom_binary)
FROM (
  SELECT x, y,
    ST_GeomFromText('POINT(' || x::text || ' ' || y::text || ')') AS geom_text,
    ST_MakePoint(x, y) AS geom_binary
  FROM (SELECT random()::float8 as x, random()::float8 as y) AS f1
) AS f2;

 spatially_equal | binary_equal | wkt_equal |     st_distance
-----------------+--------------+-----------+----------------------
 t               | f            | t         | 1.38777878078145e-16
Mike T
quelle
1
Vielen Dank für eine großartige Erklärung zur Berechnung. Ich bin neugierig auf die SQLSyntax <POINT CONSTRUCTOR METHOD>. Ist das nur ein Pseudocode, der sich auf die vier verschiedenen Ansätze bezieht, oder machen Sie eine Art Funktion?
Djq
2
@ Djq yup, es ist nur ein Platzhalter für den tatsächlichen SQL-Code in 1, 2 und 3.
Mike T
Details zu den Genauigkeitsgrenzen für den Datentyp float, der als Referenz verwendet werden soll ... Das Epsilon der Maschine ist ~ 1e-14... Ändern Sie die Tabelle f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1, um sie in Ihrer psql anzuzeigen.
Peter Krauss
5

ST_MakePoint und ST_Point sind gleich - beide rufen LWGEOM_makepoint auf (dies können Sie in der Datei postgis / postgis.sql.in im Quellcode sehen). Ich würde ST_MakePoint verwenden. Die Textkonvertierungsroutinen führen zu demselben Ergebnis, sind jedoch aufgrund des erforderlichen Parsing-Aufwands langsamer.

BradHards
quelle
1

SRID 4326 und Geometrie

Als Randnotiz zu der hervorragenden, umfassenden und aktuellen Antwort von MikeT . Viele Leute scheinen diese Frage zu stellen, weil sie die SRID auf eine POINT-Spalte setzen wollen.

CREATE TABLE foo ( geom geometry(Point,4326) );

Aber wenn sie dies tun, stoßen sie auf Probleme mit der scheinbar besten Methode, um einen Punkt zu erstellen, aber leider stoßen sie auf Probleme.

INSERT INTO foo (geom) VALUES ( ST_MakePoint(1,2) );
ERROR:  Geometry SRID (0) does not match column SRID (4326);

Aus diesem Grund haben sie zwei Möglichkeiten

  • ST_SetSRID( ST_MakePoint(1,2) )Stellen Sie die SRID manuell ein. Dies ist die am weitesten rechts stehende, aber unangenehme Einstellung
  • Konstruieren Sie aus Text mit ST_GeomFromText, dies ist logisch langsamer und benötigt keine Benchmarks: PostgreSQL muss die Argumente des Konstruktors aus dem Text analysieren. Es ist auch selbst extrem hässlich.

Leider gibt es einen anderen Weg.

Geografietyp

Die Standard-SRID für geographyist 4326. Wenn Sie neu sind, würde ich die Verwendung von geographyanstelle von vorschlagen geometry. In der Tat, im Allgemeinen, wenn Sie den Unterschied nicht kennen, den Sie wahrscheinlich wollen geography. Sie können die Spalten ziemlich einfach wechseln.

BEGIN;
  ALTER TABLE foo ADD COLUMN geog geography(point,4326);
  UPDATE foo SET geog = geom::geography;
  ALTER TABLE foo DROP COLUMN geom;
COMMIT;

Das Einfügen ist jetzt einfacher, da der Typ bereits standardmäßig mit SRID 4326 verknüpft ist. Jetzt können Sie explizit in geographydie implizite Umwandlung umwandeln oder sie einfach arbeiten lassen

ST_MakePoint(x,y)                     -- implicit cast and srid
ST_MakePoint(x,y)::geography          -- explicit cast, implicit srid
ST_SetSRID( ST_MakePoint(3,4), 4326 ) -- explicit cast and srid

Was so aussieht (alle fügen das Gleiche ein)

INSERT INTO foo (geog) VALUES
  -- implicit cast and SRID
  ( ST_MakePoint(1,2) ),

  -- explicit cast, implicit SRID
  ( ST_MakePoint(1,2)::geography ),

   -- explicit cast and SRID
  ( ST_SetSRID( ST_MakePoint(3,4), 4326 )::geography );

In Text konvertieren und dann PostgreSQL zwingen, den Text mit ST_GeomFromTextoder zu analysieren, ST_GeogFromTextist albern und langsam.

Evan Carroll
quelle