Quelle fonction pour créer un POINT dans PostGIS?

31

Lorsque vous définissez un point dans PostGIS, quand décidez-vous d'utiliser lequel des éléments suivants?

  • 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 c'est essentiellement une différence de performances, laquelle sera la plus rapide?

Nyxynyx
la source
Découvrez cette réponse: gis.stackexchange.com/a/285017/6052
Evan Carroll

Réponses:

26

Je suppose que ST_MakePointc'est le plus rapide, mais c'est assez facile à comparer avec 100 000 points aléatoires.

\timing

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

Et voici quelques résultats avec PostGIS 2.1 (trunk) sur PostgreSQL 9.1, Debian x64. Je les ai fait plusieurs fois pour obtenir une moyenne approximative. Voici l' <POINT CONSTRUCTOR METHOD>ordre du plus rapide au plus lent:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • 160 ms en moyenne
    • de loin le plus rapide et conserve une précision double point (sans perte)
    • moyen le plus simple de créer une requête paramétrée avec des données de coordonnées numériques
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • moyenne 760 ms
    • lent, car le nombre est converti en texte, puis la chaîne est reconstituée, puis PostGIS doit l'analyser pour trouver les nombres
    • avec perte, en raison du nombre -> texte -> nombre de conversions
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • moyenne 810 ms
    • le plus lent, je ne sais pas pourquoi il est plus lent que ST_GeomFromText

Enfin, une petite note de bas de page sur la différence entre les conversions sans perte / avec perte avec les méthodes ci-dessus. Ne ST_MakePointconserve que les données de précision à virgule flottante binaire et les conversions de texte tronquent une très petite partie des données. Bien que les deux points puissent avoir des différences binaires (vu dans le WKB), ils doivent toujours être spatialement égaux. Les différences de distance sont essentiellement la machine epsilon pour la double précision .

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
la source
1
Merci pour une bonne explication sur la façon de calculer cela. Je suis curieux de la SQLsyntaxe, <POINT CONSTRUCTOR METHOD>. Est-ce juste un pseudocode pour faire référence aux quatre approches différentes, ou faites-vous une sorte de fonction?
djq
2
@djq yup, c'est juste un espace réservé pour le code SQL réel en 1, 2 et 3.
Mike T
Détails sur les limites de précision du type de données float à utiliser comme référence ... La machine epsilon est ~ 1e-14... Modifiez la table f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1pour la voir dans votre psql.
Peter Krauss
5

ST_MakePoint et ST_Point sont les mêmes - ils appellent tous les deux LWGEOM_makepoint (vous pouvez le voir dans le fichier postgis / postgis.sql.in du code source). J'utiliserais ST_MakePoint. Les routines de conversion de texte produisent le même résultat, mais sont plus lentes en raison de la quantité d'analyse requise.

BradHards
la source
1

SRID 4326 et géométrie

En guise de note complémentaire à l'excellente, complète et actuelle réponse de MikeT . Beaucoup de gens semblent poser cette question car ils veulent définir le SRID sur une colonne POINT.

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

Mais quand ils le font, ils rencontrent des problèmes avec ce qui semble être la meilleure méthode pour créer un point, mais malheureusement, ils rencontrent des problèmes.

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

De là, ils pensent avoir deux options

  • Définissez le SRID manuellement, ST_SetSRID( ST_MakePoint(1,2) ) ce qui est la manière la plus à droite mais cruelle, ou
  • Construire à partir de texte en utilisant ST_GeomFromText, c'est logiquement plus lent et n'a pas besoin de repères: PostgreSQL doit analyser les arguments du constructeur à partir du texte. C'est aussi extrêmement laid lui-même.

Hélas, il existe un autre moyen.

Type de géographie

Le SRID par défaut geographyest 4326. Si vous êtes nouveau, je suggère d'utiliser à la geographyplace de geometry. En fait, généralement si vous ne connaissez pas la différence que vous voulez probablement geography. Vous pouvez changer les colonnes assez facilement.

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

L'insertion est désormais plus facile car le type est déjà associé par défaut au SRID 4326. Vous pouvez désormais effectuer un cast explicite vers geography, ou simplement laisser le cast implicite fonctionner

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

Qui ressemble à ceci, (ils insèrent tous la même chose)

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

Convertir en texte puis forcer PostgreSQL à analyser le texte avec ST_GeomFromTextou ST_GeogFromTextest stupide et lent.

Evan Carroll
la source