Fungsi apa untuk membuat POINT di PostGIS?

31

Ketika mendefinisikan suatu Poin di PostGIS, kapan Anda memutuskan untuk menggunakan mana dari yang berikut ini?

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

Jika pada dasarnya perbedaan dalam kinerja, mana yang tercepat?

Nyxynyx
sumber
Lihatlah jawaban ini: gis.stackexchange.com/a/285017/6052
Evan Carroll

Jawaban:

26

Dugaan saya adalah itu ST_MakePoint tercepat, tetapi ini cukup mudah untuk dibandingkan dengan 100k poin acak.

\timing

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

Dan berikut adalah beberapa hasil dengan PostGIS 2.1 (trunk) di PostgreSQL 9.1, x64 Debian. Saya melakukannya beberapa kali untuk mendapatkan perkiraan rata-rata. Berikut <POINT CONSTRUCTOR METHOD>urutan dari tercepat ke terlambat:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • rata-rata 160 ms
    • sejauh ini tercepat, dan mempertahankan presisi titik ganda (lossless)
    • cara termudah untuk membuat kueri parameter dengan data koordinat numerik
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • rata-rata 760 ms
    • lambat, karena nomor dilemparkan ke teks, maka string disatukan, maka PostGIS perlu menguraikannya untuk menemukan angka
    • lossy, karena nomor -> teks -> konversi nomor
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • rata-rata 810 ms
    • paling lambat, tidak yakin mengapa ini lebih lambat dari ST_GeomFromText

Terakhir, catatan kaki kecil tentang perbedaan antara konversi lossless / lossy dengan metode di atas. Hanya ST_MakePointmenyimpan data presisi titik mengambang biner, dan konversi teks akan memotong sebagian kecil data. Meskipun kedua poin tersebut mungkin memiliki perbedaan biner (terlihat di WKB), mereka harus selalu sama secara spasial. Perbedaan jarak pada dasarnya adalah epsilon mesin untuk presisi ganda .

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
sumber
1
Terima kasih atas penjelasan yang bagus tentang cara menghitung ini. Saya ingin tahu tentang SQLsintaks <POINT CONSTRUCTOR METHOD>,. Apakah itu hanya kodesemu untuk merujuk pada empat pendekatan yang berbeda, atau apakah Anda membuat semacam fungsi?
djq
2
@djq ya, itu hanya pengganti untuk kode SQL aktual dalam 1, 2 dan 3.
Mike T
Detail tentang batas presisi pada float datatype untuk digunakan sebagai referensi ... Mesin epsilon adalah ~ 1e-14... Ubah tabel f1 FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1untuk melihatnya di psql Anda.
Peter Krauss
5

ST_MakePoint dan ST_Point sama - keduanya memanggil LWGEOM_makepoint (Anda dapat melihat ini di file postgis / postgis.sql.in dalam kode sumber). Saya akan menggunakan ST_MakePoint. Rutin konversi teks menghasilkan hasil yang sama, tetapi lebih lambat karena jumlah parsing yang diperlukan.

BradHards
sumber
1

SRID 4326 dan Geometri

Sebagai catatan untuk jawaban yang sangat baik, komprehensif, dan saat ini oleh MikeT . Banyak orang tampaknya mengajukan pertanyaan ini karena mereka ingin mengatur SRID pada kolom TITIK.

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

Tetapi ketika mereka melakukannya mereka mengalami masalah dengan apa yang tampaknya merupakan metode terbaik untuk menciptakan suatu poin, tetapi sayangnya mereka mengalami masalah.

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

Dari sana, mereka beralasan memiliki dua opsi

  • Atur SRID secara manual, ST_SetSRID( ST_MakePoint(1,2) )yang merupakan cara paling kanan tetapi kekar, atau
  • Buat dari teks menggunakan ST_GeomFromText, ini lebih lambat secara logis dan tidak perlu benchmark: PostgreSQL harus menguraikan argumen konstruktor dari teks. Itu juga sangat jelek.

Sayangnya, ada cara lain.

Jenis Geografi

SRID default untuk geographyadalah 4326. Jika Anda baru, saya sarankan menggunakan geographysebagai gantinya geometry. Bahkan, umumnya jika Anda tidak tahu perbedaan yang mungkin Anda inginkan geography. Anda dapat mengganti kolom dengan cukup mudah.

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

Sekarang penyisipan lebih mudah karena jenisnya sudah dikaitkan dengan default dengan SRID 4326. Sekarang Anda dapat secara eksplisit dilemparkan ke geography, atau biarkan saja karya pemeran implisit bekerja

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

Yang terlihat seperti ini, (mereka semua memasukkan hte hal yang sama)

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

Konversi ke teks dan kemudian memaksa PostgreSQL untuk mem-parsing teks dengan ST_GeomFromTextatau ST_GeogFromTextkonyol dan lambat.

Evan Carroll
sumber