Qual função para criar um PONTO no PostGIS?


31

Ao definir um ponto no PostGIS, quando você decide usar qual dos seguintes?

  • 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 é essencialmente uma diferença no desempenho, qual será o mais rápido?


Respostas:


26

Meu palpite é que ST_MakePointé o mais rápido, mas isso é fácil o suficiente para ser comparado com 100 mil pontos aleatórios.

\timing

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

E aqui estão alguns resultados com o PostGIS 2.1 (tronco) no PostgreSQL 9.1, x64 Debian. Eu as fiz algumas vezes para obter uma média aproximada. Aqui estão os <POINT CONSTRUCTOR METHOD>ordem do mais rápido para o mais lento:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • média 160 ms
    • muito mais rápido e preserva a precisão de dois pontos (sem perdas)
    • maneira mais fácil de fazer uma consulta parametrizada com dados de coordenadas numéricas
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • média 760 ms
    • lento, como o número é convertido em texto, a sequência é montada e o PostGIS precisa analisá-la para encontrar os números
    • com perdas, devido a conversões de número -> texto -> número
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • média de 810 ms
    • mais lento, sem saber por que é mais lento que ST_GeomFromText

Por fim, uma pequena nota de rodapé sobre a diferença entre conversões sem perdas / perdas com os métodos acima. ST_MakePointPreserva apenas os dados binários de precisão do ponto flutuante e as conversões de texto truncam uma parte muito pequena dos dados. Embora os dois pontos possam ter diferenças binárias (vistas no WKB), eles sempre devem ser espacialmente iguais. As diferenças de distância são essencialmente o epsilon da máquina para precisão dupla .

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

11
Obrigado por uma ótima explicação sobre como calcular isso. Estou curioso sobre a SQLsintaxe <POINT CONSTRUCTOR METHOD>. Isso é apenas um pseudocódigo para se referir às quatro abordagens diferentes ou você está fazendo algum tipo de função?
DJQ

2
@djq yup, é apenas um espaço reservado para o código SQL real em 1, 2 e 3.
Mike T

Detalhe sobre os limites de precisão no tipo de dados flutuante para usar como referência ... O epsilon da máquina é ~ 1e-14... Altere a tabela f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1para vê-la em seu psql.
Peter Krauss

5

ST_MakePoint e ST_Point são iguais - ambos chamam LWGEOM_makepoint (você pode ver isso no arquivo postgis / postgis.sql.in no código-fonte). Eu usaria ST_MakePoint. As rotinas de conversão de texto produzem o mesmo resultado, mas são mais lentas devido à quantidade de análise necessária.


1

SRID 4326 e Geometria

Como observação à excelente, abrangente e atual resposta de MikeT . Muitas pessoas parecem fazer essa pergunta porque desejam definir o SRID em uma coluna POINT.

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

Mas, quando o fazem, encontram problemas com o que parece ser o melhor método para criar um argumento, mas, infelizmente, encontram problemas.

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

A partir daí, eles raciocinam que têm duas opções

  • Defina o SRID manualmente, ST_SetSRID( ST_MakePoint(1,2) )que é o caminho mais à direita, mas com crosta, ou
  • Construa a partir do texto usando ST_GeomFromText, isso é logicamente mais lento e não precisa de benchmarks: o PostgreSQL precisa analisar os argumentos do construtor a partir do texto. Também é extremamente feio em si.

Infelizmente, existe outro caminho.

Tipo de Geografia

O SRID padrão geographyé 4326. Se você é novo, sugiro usar em geographyvez de geometry. De fato, geralmente se você não sabe a diferença que provavelmente deseja geography. Você pode mudar as colunas facilmente.

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

Agora, a inserção é mais fácil porque o tipo já está associado ao padrão com o SRID 4326. Agora você pode converter explicitamente para geography, ou apenas deixar a conversão implícita funcionar

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 parece com isso (todos eles inserem a mesma coisa)

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

Converter em texto e forçar o PostgreSQL a analisar o texto com ST_GeomFromTextou ST_GeogFromTexté bobo e lento.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.