PostGIS'te POINT oluşturmak için hangi fonksiyon?


30

PostGIS’te bir Nokta tanımlarken, aşağıdakilerden hangisini kullanmaya karar verdiniz?

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

Esasen performansta bir fark varsa, hangisi en hızlı olacak?


Yanıtlar:


26

Benim tahminim bu ST_MakePointen hızlı, ancak bu 100k rastgele puan ile kıyaslama yapmak için yeterince kolaydır.

\timing

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

Ve burada PostgreSQL 9.1, x64 Debian'daki PostGIS 2.1 (trunk) sonuçları da var. Onlara yaklaşık bir ortalama elde etmek için birkaç kez yaptım. En <POINT CONSTRUCTOR METHOD>hızlıdan en yavaşa doğru olan sıralamalar:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • ortalama 160 ms
    • çok hızlı ve çift nokta hassasiyetini korur (kayıpsız)
    • Sayısal koordinat verileriyle parametreli sorgu yapmak için en kolay yol
  2. ST_GeomFromText('POINT(' || random()::text || ' ' || random()::text || ')', 4326)
    • ortalama 760 ms
    • sayı metne dönüştürüldüğü için yavaş, sonra dize bir araya getirilir, sonra PostGIS'in sayıları bulmak için ayrıştırması gerekir.
    • kayıp - sayı -> metin -> sayı dönüşümleri nedeniyle
  3. ST_GeomFromEWKT('SRID=4326;POINT(' || random()::text || ' ' || random()::text || ')')
    • ortalama 810 ms
    • en yavaş, neden olduğundan daha yavaş olduğundan emin değil ST_GeomFromText

Son olarak, yukarıdaki yöntemlerle kayıpsız / kayıpsız dönüşümler arasındaki farka ilişkin bir dipnot. Yalnızca ST_MakePointikili kayan nokta hassasiyetli verilerini korur ve metin dönüşümleri verilerin çok küçük bir bölümünü keser. İki noktanın (WKB'de görüldüğü gibi) ikili farklılıkları olsa da, her zaman mekansal olarak eşit olmaları gerekir. Mesafe farkları aslında çift ​​hassasiyet için makine epsilon'udur .

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
Bunun nasıl hesaplanacağına dair harika bir açıklama için teşekkürler. SQLSözdizimini merak ediyorum <POINT CONSTRUCTOR METHOD>. Bu sadece dört farklı yaklaşıma atıfta bulunan sahte kod mu, yoksa bir tür işlev mi yapıyorsunuz?
djq

2
@djq yup, 1, 2 ve 3'teki gerçek SQL kodu için sadece bir yer tutucudur.
Mike T

Referans olarak kullanılacak kayan veri tipindeki hassasiyet sınırları hakkında detaylar ... Makine epsilon ~ 1e-14... FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1psql içinde görmek için f1 tablosunu değiştirin .
Peter Krauss

5

ST_MakePoint ve ST_Point aynıdır - ikisi de LWGEOM_makepoint'i çağırır (bunu kaynak kodundaki postgis / postgis.sql.in dosyasında görebilirsiniz). ST_MakePoint kullanırdım. Metin dönüştürme yordamları aynı sonucu verir, ancak gereken ayrıştırma miktarı nedeniyle daha yavaştır.


1

SRID 4326 ve Geometri

MikeT'nin mükemmel, kapsamlı ve güncel cevabına bir not olarak . Birçok kişi bu soruyu soruyor gibi görünüyor, çünkü SRID'yi POINT sütununa ayarlamak istiyorlar.

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

Fakat bunu yaptıklarında, bir nokta yaratmanın en iyi yöntemi gibi görünen problemlerle karşılaşırlar, ancak ne yazık ki başları belaya girerler.

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

Oradan iki seçeneğe sahip olma nedeni

  • ST_SetSRID( ST_MakePoint(1,2) )SRID’yi manuel olarak ayarlayın; bu, en doğru yoldur ancak
  • Kullanarak metinden yapılandırın ST_GeomFromText, bu mantıksal olarak yavaştır ve kıyaslamalara gerek duymaz: PostgreSQL, yapıcının argümanlarını metinden ayrıştırmak zorundadır. Aynı zamanda son derece çirkin kendisi.

Ne yazık ki, başka bir yol var.

Coğrafya Türü

İçin varsayılan SRID geographydeğeri 4326'dır. Yeniyseniz, geographyyerine kullanmanızı öneririm geometry. Aslında, genellikle istediğiniz farkı bilmiyorsanız geography. Sütunları kolayca değiştirebilirsiniz.

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

Türü zaten açıkça yayın yapabilirsiniz Şimdi SRID 4326. ile ilişkili default çünkü artık ekleme daha kolaydır geography, ya da sadece örtülü cast çalışmasına izin

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

Hangi şeye benziyor, (hepsi aynı şeyi ekler)

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

Metne dönüştürme ve daha sonra metni ayrıştırmak için PostgreSQL zorlayarak ST_GeomFromTextveya ST_GeogFromTextsaçma ve yavaştır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.