在PostGIS中创建POINT的功能是什么?


Answers:


26

我的猜测是ST_MakePoint最快,但这很容易用10万个随机点进行基准测试。

\timing

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

以下是PostgreSQL 9.1,x64 Debian上的PostGIS 2.1(trunk)的一些结果。我做了几次,以获得一个近似的平均值。以下是<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 2013年

2
@djq烨,它只是一个在1,2和3。实际的SQL代码占位符
麦克ŧ

有关用作参考的float数据类型的精度限制的详细信息...机器epsilon为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。文本转换例程产生相同的结果,但由于需要大量的解析,因此速度较慢。


1

SRID 4326和几何

作为对MikeT出色,全面和最新答案的补充说明。许多人似乎会问这个问题,因为他们想在POINT列上设置SRID。

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必须从文本中解析构造函数的参数。它本身也非常丑陋。

las,还有另一种方式。

地理类型

的默认SRID geography是4326。如果您是新手,建议您使用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是愚蠢且缓慢的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.