Какая функция для создания POINT в PostGIS?

31

Когда вы определяете точку в PostGIS, когда вы решаете использовать что из следующего?

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

Если это существенно разница в производительности, что будет самым быстрым?

Nyxynyx
источник
Проверьте этот ответ: gis.stackexchange.com/a/285017/6052
Эван Кэрролл

Ответы:

26

Я предполагаю, что ST_MakePointэто самый быстрый, но это достаточно легко для сравнения с 100k случайных точек.

\timing

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

И вот некоторые результаты с PostGIS 2.1 (транк) на PostgreSQL 9.1, x64 Debian. Я сделал их несколько раз, чтобы получить приблизительное среднее. Вот <POINT CONSTRUCTOR METHOD>порядок от самого быстрого до самого медленного:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • в среднем 160 мс
    • намного быстрее и сохраняет точность в две точки (без потерь)
    • Самый простой способ сделать параметризованный запрос с числовыми данными координат
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • в среднем 760 мс
    • медленно, так как число преобразуется в текст, затем строка соединяется вместе, затем PostGIS должен проанализировать ее, чтобы найти числа
    • с потерями, из-за числа -> текст -> число преобразований
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • в среднем 810 мс
    • самый медленный, не уверен, почему это медленнее, чем ST_GeomFromText

И, наконец, небольшая сноска о разнице между конверсиями без потерь / с потерями с помощью вышеуказанных методов. ST_MakePointСохраняет только двоичные данные с плавающей запятой, а преобразования текста обрезают очень небольшую часть данных. Хотя эти две точки могут иметь двоичные различия (видно в WKB), они всегда должны быть пространственно равными. Различия в расстояниях - это, по сути, машина эпсилон для двойной точности .

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
Спасибо за отличное объяснение о том, как рассчитать это. Мне любопытно по поводу SQLсинтаксиса <POINT CONSTRUCTOR METHOD>. Это просто псевдокод для обозначения четырех разных подходов, или вы выполняете какую-то функцию?
DJQ
2
@djq Да, это просто заполнитель для реального кода SQL в 1, 2 и 3.
Майк Т,
Подробно о предельных значениях точности для типа данных с плавающей запятой, который будет использоваться в качестве эталонного ... Эпсилон машины - это ~ 1e-14... Измените таблицу f1, FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1чтобы увидеть ее в psql.
Питер Краусс
5

ST_MakePoint и ST_Point одинаковы - оба они вызывают LWGEOM_makepoint (вы можете увидеть это в файле postgis / postgis.sql.in в исходном коде). Я бы использовал ST_MakePoint. Процедуры преобразования текста дают тот же результат, но медленнее из-за необходимого количества синтаксического анализа.

BradHards
источник
1

SRID 4326 и геометрия

В качестве примечания к отличному, всеобъемлющему и актуальному ответу MikeT . Многие люди задаются этим вопросом, потому что хотят установить SRID в столбце POINT.

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

Но когда они это делают, у них возникают проблемы с тем, что кажется лучшим способом создания точки, но, увы, они сталкиваются с проблемами.

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

Оттуда они думают, что у них есть два варианта

  • Установите SRID вручную, ST_SetSRID( ST_MakePoint(1,2) )что является самым правильным способом, но хитрым, или
  • Построение из текста с использованием ST_GeomFromText, это логически медленнее и не требует тестов: PostgreSQL должен анализировать аргументы конструктора из текста. Это также чрезвычайно уродливо само по себе.

Увы, есть и другой путь.

Тип географии

SRID по умолчанию для geography4326. Если вы новичок, я бы предложил использовать geographyвместо geometry. На самом деле, как правило, если вы не знаете разницу, которую вы, вероятно, хотите geography. Вы можете легко переключать столбцы.

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

Теперь вставка стала проще, потому что тип уже связан по умолчанию с SRID 4326. Теперь вы можете явно приводить к geographyили просто позволить неявному приведению работать

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

Который выглядит так, (они все вставляют одно и то же)

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

Преобразование в текст, а затем принуждение PostgreSQL к анализу текста с ST_GeomFromTextили ST_GeogFromTextглупо и медленно.

Эван Кэрролл
источник