Quale funzione per creare un PUNTO in PostGIS?


31

Quando si definisce un punto in PostGIS, quando si decide di utilizzare quale dei seguenti?

  • 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)')

Se è essenzialmente una differenza nelle prestazioni, quale sarà la più veloce?


Risposte:


26

La mia ipotesi è che ST_MakePointsia il più veloce, ma questo è abbastanza facile da confrontare con 100k punti casuali.

\timing

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

E qui ci sono alcuni risultati con PostGIS 2.1 (trunk) su PostgreSQL 9.1, Debian x64. Li ho fatti alcune volte per ottenere una media approssimativa. Qui ci sono <POINT CONSTRUCTOR METHOD>in ordine dal più veloce al più lento:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • media 160 ms
    • di gran lunga più veloce e preserva la precisione a doppio punto (senza perdita)
    • il modo più semplice per eseguire una query con parametri con dati di coordinate numeriche
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • media 760 ms
    • lento, poiché il numero viene convertito in testo, quindi la stringa viene messa insieme, quindi PostGIS deve analizzarla per trovare i numeri
    • con perdita di dati, dovuta al numero -> testo -> conversioni numeriche
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • media 810 ms
    • più lento, non so perché sia ​​più lento di ST_GeomFromText

Infine, una nota a piè di pagina sulla differenza tra conversioni lossless / lossy con i metodi di cui sopra. ST_MakePointConserva solo i dati binari di precisione in virgola mobile e le conversioni di testo troncano una parte molto piccola dei dati. Sebbene i due punti possano avere differenze binarie (viste nel WKB), dovrebbero sempre essere spazialmente uguali. Le differenze di distanza sono essenzialmente la macchina epsilon per la doppia precisione .

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

1
Grazie per un'ottima spiegazione su come calcolare questo. Sono curioso di sapere la SQLsintassi <POINT CONSTRUCTOR METHOD>. È solo uno pseudocodice per riferirsi ai quattro diversi approcci o stai facendo qualche tipo di funzione?
djq

2
@djq yup, è solo un segnaposto per il codice SQL effettivo in 1, 2 e 3.
Mike T

Dettagli sui limiti di precisione sul tipo di dati float da utilizzare come riferimento ... La macchina epsilon è ~ 1e-14... Cambia la tabella f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1per vederla nel tuo psql.
Peter Krauss,

5

ST_MakePoint e ST_Point sono uguali: entrambi chiamano LWGEOM_makepoint (puoi vederlo nel file postgis / postgis.sql.in nel codice sorgente). Vorrei usare ST_MakePoint. Le routine di conversione del testo producono lo stesso risultato, ma sono più lente a causa della quantità di analisi richiesta.


1

SRID 4326 e geometria

Come nota a margine dell'eccellente, completa e attuale risposta di MikeT . Molte persone sembrano porre questa domanda perché vogliono impostare lo SRID su una colonna POINT.

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

Ma quando lo fanno incontrano problemi con quello che sembra il metodo migliore per creare un punto, ma purtroppo si trovano in difficoltà.

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

Da lì, pensano di avere due opzioni

  • Impostare manualmente l'SRID, ST_SetSRID( ST_MakePoint(1,2) )che è il modo più giusto ma crufty, o
  • Costruisci usando il testo ST_GeomFromText, questo è logicamente più lento e non ha bisogno di parametri di riferimento: PostgreSQL deve analizzare gli argomenti del costruttore dal testo. È anche estremamente brutto stesso.

Ahimè, c'è un altro modo.

Tipo di geografia

L'SRID predefinito per geographyè 4326. Se sei nuovo, suggerirei di utilizzare geographyinvece di geometry. In effetti, generalmente se non conosci la differenza che probabilmente desideri geography. Puoi cambiare le colonne abbastanza facilmente.

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

Ora l'inserimento è più semplice perché il tipo è già associato per impostazione predefinita a SRID 4326. Ora è possibile eseguire il cast esplicito geographyo semplicemente consentire al cast implicito di funzionare

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

Che assomiglia a questo, (tutti inseriscono la stessa cosa)

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 );

La conversione in testo e quindi forzare PostgreSQL a analizzare il testo con ST_GeomFromTexto ST_GeogFromTextè sciocco e lento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.