ฟังก์ชันใดในการสร้าง POINT ใน PostGIS


30

เมื่อกำหนดจุดใน 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)')

หากเป็นหลักความแตกต่างในการปฏิบัติงานซึ่งจะเร็วที่สุด?


ลองดูคำตอบนี้: gis.stackexchange.com/a/285017/6052
Evan Carroll

คำตอบ:


26

ฉันเดาว่าST_MakePointมันเร็วที่สุด แต่มันง่ายพอที่จะเปรียบเทียบกับคะแนนสุ่ม 100k

\timing

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

และนี่คือผลลัพธ์บางส่วนที่มี PostGIS 2.1 (trunk) บน PostgreSQL 9.1, x64 Debian ฉันทำพวกมันสองสามครั้งเพื่อให้ได้ค่าเฉลี่ยโดยประมาณ นี่คือ<POINT CONSTRUCTOR METHOD>ลำดับจากเร็วไปช้า:

  1. ST_SetSRID(ST_MakePoint(random(), random()), 4326)
    • เฉลี่ย 160 ms
    • เร็วที่สุดและรักษาความแม่นยำสองจุด (lossless)
    • วิธีที่ง่ายที่สุดในการสร้างเคียวรีแบบพารามิเตอร์ด้วยข้อมูลพิกัดตัวเลข
  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) แต่ก็ควรมีความเสมอภาคเชิงพื้นที่ ความแตกต่างทางไกลเป็นหลักepsilon เครื่องแม่นยำสอง

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 yup เป็นเพียงตัวยึดสำหรับรหัส SQL ที่แท้จริงใน 1, 2 และ 3
Mike T

รายละเอียดเกี่ยวกับขีด จำกัด ความแม่นยำของประเภทข้อมูลลอยที่จะใช้เป็นข้อมูลอ้างอิง ... เครื่อง epsilon คือ ~ 1e-14... เปลี่ยนตาราง f1 เป็น FROM (SELECT random()::float8 as x, random()::float8 as y UNION SELECT 12.24343484842,34.58384538483434) AS f1เพื่อดูใน psql ของคุณ
Peter Krauss

5

ST_MakePoint และ ST_Point เหมือนกัน - ทั้งคู่เรียก LWGEOM_makepoint (คุณสามารถดูได้ในไฟล์ postgis / postgis.sql.in ในซอร์สโค้ด) ฉันจะใช้ ST_MakePoint รูทีนการแปลงข้อความให้ผลลัพธ์เหมือนกัน แต่ช้ากว่าเนื่องจากจำนวนการแยกวิเคราะห์ที่จำเป็น


1

SRID 4326 และเรขาคณิต

เป็นบันทึกทางด้านคำตอบที่ดีเยี่ยมครอบคลุมและในปัจจุบันโดย MikeT หลายคนดูเหมือนจะถามคำถามนี้เพราะต้องการตั้งค่า 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) )ซึ่งเป็นวิธีที่เหมาะสมที่สุด แต่ crufty หรือ
  • สร้างจากการใช้ข้อความST_GeomFromTextสิ่งนี้ช้าลงอย่างมีเหตุมีผลและไม่จำเป็นต้องใช้มาตรฐาน: PostgreSQL ต้องแยกอาร์กิวเมนต์ของตัวสร้างจากข้อความ มันก็น่าเกลียดอย่างยิ่ง

อนิจจามีวิธีอื่น

ประเภทภูมิศาสตร์

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

ซึ่งดูเหมือนว่านี้ (พวกเขาทั้งหมดแทรกสิ่งเดียวกัน hte)

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โง่และช้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.