Chức năng nào để tạo ĐIỂM trong PostGIS?


30

Khi xác định một Điểm trong PostGIS, khi nào bạn quyết định sử dụng điểm nào sau đây?

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

Nếu nó về cơ bản là một sự khác biệt trong hiệu suất, đó sẽ là nhanh nhất?


Kiểm tra câu trả lời này: gis.stackexchange.com/a/285017/6052
Evan Carroll

Câu trả lời:


26

Tôi đoán là ST_MakePointnhanh nhất, nhưng điều này đủ dễ để điểm chuẩn với 100k điểm ngẫu nhiên.

\timing

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

Và đây là một số kết quả với PostGIS 2.1 (trung kế) trên PostgreQuery 9.1, x64 Debian. Tôi đã làm chúng một vài lần để có được mức trung bình gần đúng. Dưới đây là <POINT CONSTRUCTOR METHOD>thứ tự từ nhanh nhất đến chậm nhất:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • trung bình 160 ms
    • nhanh nhất và bảo toàn độ chính xác hai điểm (lossless)
    • Cách dễ nhất để thực hiện một truy vấn được tham số hóa với dữ liệu tọa độ số
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • trung bình 760 ms
    • chậm, vì số được chuyển thành văn bản, sau đó chuỗi được nối với nhau, sau đó PostGIS cần phân tích cú pháp để tìm số
    • mất mát, do số -> văn bản -> chuyển đổi số
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • trung bình 810 ms
    • chậm nhất, không chắc tại sao nó chậm hơn ST_GeomFromText

Cuối cùng, một chú thích nhỏ về sự khác biệt giữa chuyển đổi lossless / lossy với các phương pháp trên. Chỉ ST_MakePointbảo tồn dữ liệu chính xác của dấu phẩy động nhị phân và chuyển đổi văn bản cắt bớt một phần rất nhỏ của dữ liệu. Mặc dù hai điểm có thể có sự khác biệt nhị phân (được nhìn thấy trong WKB), chúng phải luôn luôn bằng nhau về mặt không gian. Sự khác biệt về khoảng cách về cơ bản là máy epsilon cho độ chính xác gấp đôi .

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
Cảm ơn cho một lời giải thích tuyệt vời về cách tính toán này. Tôi tò mò về SQLcú pháp , <POINT CONSTRUCTOR METHOD>. Có phải đó chỉ là mã giả để chỉ bốn phương pháp khác nhau, hay bạn đang thực hiện một số loại chức năng?
djq

2
@djq yup, nó chỉ là một trình giữ chỗ cho mã SQL thực tế trong 1, 2 và 3.
Mike T

Chi tiết về các giới hạn chính xác trên kiểu dữ liệu float để sử dụng làm tham chiếu ... epsilon của máy là ~ 1e-14... Thay đổi bảng F1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1để xem nó trong psql của bạn.
Peter Krauss

5

ST_MakePoint và ST_Point giống nhau - cả hai đều gọi LWGEOM_makepoint (bạn có thể thấy điều này trong tệp postgis / postgis.sql.in trong mã nguồn). Tôi sẽ sử dụng ST_MakePoint. Các thói quen chuyển đổi văn bản tạo ra cùng một kết quả, nhưng chậm hơn vì số lượng phân tích được yêu cầu.


1

SRID 4326 và Hình học

Như một lưu ý phụ cho câu trả lời xuất sắc, toàn diện và hiện tại của MikeT . Nhiều người dường như hỏi câu hỏi này vì họ muốn đặt SRID trên cột POINT.

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

Nhưng khi họ làm họ gặp vấn đề với những gì có vẻ như là phương pháp tốt nhất để tạo điểm, nhưng than ôi họ gặp rắc rối.

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

Từ đó, họ lý do họ có hai lựa chọn

  • Đặt SRID theo cách thủ công, ST_SetSRID( ST_MakePoint(1,2) ) đó là cách đúng nhất nhưng cực kỳ hay
  • Xây dựng từ văn bản bằng cách sử dụng ST_GeomFromText, điều này chậm hơn về mặt logic và không cần điểm chuẩn: PostgreQuery phải phân tích các đối số của hàm tạo từ văn bản. Bản thân nó cũng cực kỳ xấu xí.

Than ôi, có một cách khác.

Loại địa lý

SRID mặc định cho geographylà 4326. Nếu bạn là người mới, tôi sẽ đề xuất sử dụng geographythay vì geometry. Trên thực tế, nói chung nếu bạn không biết sự khác biệt mà bạn có thể muốn geography. Bạn có thể chuyển đổi các cột khá dễ dàng.

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

Bây giờ việc chèn trở nên dễ dàng hơn vì loại này đã được liên kết mặc định với SRID 4326. Bây giờ bạn có thể chuyển sang một cách rõ ràng geographyhoặc chỉ để cho phép truyền ẩn hoạt động

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

Trông giống như thế này, (tất cả đều chèn hte cùng một thứ)

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

Chuyển đổi thành văn bản và sau đó buộc PostgreSQL phân tích văn bản bằng ST_GeomFromTexthoặc ST_GeogFromTextlà ngớ ngẩn và chậm chạp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.