¿Qué función para crear un PUNTO en PostGIS?

31

Al definir un Punto en PostGIS, ¿cuándo decide usar cuál de los siguientes?

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

Si es esencialmente una diferencia en el rendimiento, ¿cuál será el más rápido?

Nyxynyx
fuente
Mira esta respuesta: gis.stackexchange.com/a/285017/6052
Evan Carroll

Respuestas:

26

Supongo que ST_MakePointes más rápido, pero esto es lo suficientemente fácil de comparar con 100k puntos aleatorios.

\timing

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

Y aquí hay algunos resultados con PostGIS 2.1 (troncal) en PostgreSQL 9.1, x64 Debian. Los hice varias veces para obtener un promedio aproximado. Aquí están los <POINT CONSTRUCTOR METHOD>ordenados de más rápido a más lento:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • promedio 160 ms
    • mucho más rápido y conserva la precisión de doble punto (sin pérdidas)
    • La forma más fácil de hacer una consulta parametrizada con datos numéricos de coordenadas
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • promedio 760 ms
    • lento, a medida que el número se convierte en texto, la cadena se junta, luego PostGIS necesita analizarlo para encontrar los números
    • con pérdida, debido al número -> texto -> conversiones de números
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • promedio 810 ms
    • más lento, no estoy seguro de por qué es más lento que ST_GeomFromText

Por último, una pequeña nota al pie de página sobre la diferencia entre las conversiones sin pérdida / pérdida con los métodos anteriores. Solo ST_MakePointconserva los datos de precisión de punto flotante binario, y las conversiones de texto truncan una parte muy pequeña de los datos. Aunque los dos puntos pueden tener diferencias binarias (vistas en el WKB), siempre deben ser espacialmente iguales. Las diferencias de distancia son esencialmente la máquina épsilon para doble precisión .

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
fuente
1
Gracias por una gran explicación sobre cómo calcular esto. Tengo curiosidad acerca de la SQLsintaxis, <POINT CONSTRUCTOR METHOD>. ¿Es solo pseudocódigo para referirse a los cuatro enfoques diferentes, o está haciendo algún tipo de función?
djq
2
@djq sí, es solo un marcador de posición para el código SQL real en 1, 2 y 3.
Mike T
Detalles sobre los límites de precisión en el tipo de datos flotantes para usar como referencia ... La máquina epsilon es ~ 1e-14... Cambie la tabla f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1para verla en su psql.
Peter Krauss
5

ST_MakePoint y ST_Point son iguales: ambos llaman a LWGEOM_makepoint (puede ver esto en el archivo postgis / postgis.sql.in en el código fuente). Yo usaría ST_MakePoint. Las rutinas de conversión de texto producen el mismo resultado, pero son más lentas debido a la cantidad de análisis que se requiere.

BradHards
fuente
1

SRID 4326 y Geometría

Como nota al margen de la excelente, completa y actual respuesta de MikeT . Muchas personas parecen hacer esta pregunta porque quieren establecer el SRID en una columna POINT.

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

Pero cuando lo hacen, se topan con problemas con lo que parece ser el mejor método para crear un punto, pero lamentablemente se topan con problemas.

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

A partir de ahí, razonan que tienen dos opciones

  • Establezca el SRID manualmente, ST_SetSRID( ST_MakePoint(1,2) )que es la forma más correcta pero crujiente, o
  • Construir a partir de texto usando ST_GeomFromText, esto es lógicamente más lento y no necesita puntos de referencia: PostgreSQL tiene que analizar los argumentos del constructor a partir del texto. También es extremadamente feo en sí mismo.

Por desgracia, hay otra manera.

Tipo de geografía

El SRID predeterminado para geographyes 4326. Si es nuevo, sugeriría usar en geographylugar de geometry. De hecho, generalmente si no conoce la diferencia que probablemente quiera geography. Puede cambiar las columnas con bastante facilidad.

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

Ahora la inserción es más fácil porque el tipo ya está asociado por defecto con SRID 4326. Ahora puede convertir explícitamente geographyo simplemente dejar que la conversión implícita funcione

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

Que se ve así, (todos insertan lo mismo)

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 conversión a texto y luego obliga a PostgreSQL a analizar el texto con ST_GeomFromTexto ST_GeogFromTextes tonto y lento.

Evan Carroll
fuente