วิธีแก้ไขปัญหาประสิทธิภาพใน PostGIS ST_Intersects


9

ฉันเป็นมือใหม่ใน postgis และฉันมีปัญหาในการค้นหา

นี่แบบสอบถามของฉัน:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

และปัญหาก็คือรูปหลายเหลี่ยมของฉันมีรูปหลายเหลี่ยมขนาดใหญ่มาก (หน้ายาว 600 หน้าใน word word!) และใช้เวลาดำเนินการนานกว่า 2 ชั่วโมง!

มีวิธีเพิ่มประสิทธิภาพข้อความค้นหาของฉันหรือใช้วิธีอื่นได้หรือไม่

กรุณาช่วยให้คุณชื่นชมอย่างมาก!

คำตอบ:


8

สิ่งที่คุณควรทำคือใส่รูปหลายเหลี่ยมขนาดใหญ่ในตารางเป็นรูปหลายเหลี่ยมเดียว (พร้อม ST_Dump) แล้วใส่ดัชนีลงไป สิ่งที่ต้องการ:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

นั่นควรเป็นวิธีที่เร็วกว่าด้วยเหตุผลหลายประการ


ขอบคุณ Nicklas สำหรับคำตอบที่ยอดเยี่ยมนี้ ขอโทษฉันพลาดที่จะพูดถึงว่าฉันมีรูปหลายเหลี่ยมมากกว่าหนึ่งและพวกเขาจะถูกเก็บไว้ในตารางที่มีดัชนีแล้ว แต่ฉันควรให้ข้อมูล geom โดยตรงจะเร็วขึ้น อย่างไรก็ตามฉันลองวิธีที่คุณแนะนำ แต่ก็ยังใช้เวลานานมาก! ข้อเสนอแนะอื่น ๆ ?
ซาร่า

@Sara ตกลงดังนั้นคุณลองแยก multigeoemtries เป็น geometries เดียวตามที่ฉันแนะนำด้วย ST_Dump หรือไม่
Nicklas Avén

เราพูดถึงตำแหน่งผู้ใช้กี่ตำแหน่ง รูปหลายเหลี่ยมขนาดใหญ่กี่อัน คุณได้อะไรจาก SELECT ST_npoints (geom) จาก big_polygons_table;?
Nicklas Avén

ขออภัยฉันไม่ดีให้ฉันอธิบายเพิ่มเติมเกี่ยวกับตารางของฉันเพื่อให้ชัดเจนยิ่งขึ้นสำหรับคุณ: ฉันมี table1 ซึ่งมีคอลัมน์ geom ที่มีประมาณ 230 แถวและในแต่ละแถวมีหลายรูปหลายเหลี่ยม และมีดัชนีในคอลัมน์ _geom Table2 ซึ่งประกอบด้วยคอลัมน์ตำแหน่ง (คะแนน), การประทับเวลา, ID ผู้ใช้และ ID (pk) และ 3 ดัชนีที่สร้างขึ้นโดยใช้ (ตำแหน่ง, การประทับเวลา, หมายเลขผู้ใช้) ตารางนี้มีขนาดใหญ่มากประมาณ 103496003 แถวจำนวนสูงสุดของ ST_npoints คือ 1440430 16. ฉันขอโทษถ้าฉันทำให้คุณสับสน แต่ฉันต้องการความช่วยเหลือจากคุณจริงๆ! ขอบคุณ
Sara

2

ขึ้นอยู่กับคุณภาพความแม่นยำที่คุณต้องการ คุณสามารถลดความซับซ้อนของรูปหลายเหลี่ยมได้ง่ายโดยใช้: http://postgis.net/docs/ST_Simplify.html

สิ่งที่ฉันทำบ่อยครั้งระหว่างการพัฒนาแอปพลิเคชัน GIS ของฉันคือการคิดถึงวิธีที่ดีที่สุดในการลดข้อมูลให้น้อยที่สุด เช่น. เลือกรูปหลายเหลี่ยมล่วงหน้าภายในกล่องขอบเขตตัวอย่างเช่น - ขึ้นอยู่กับ zoomlevel คุณไม่ต้องการผลลัพธ์ที่แม่นยำเป็นพิเศษ (st_simplify) เป็นต้น ...

หวังว่าจะช่วยคุณได้เล็กน้อย!


ขอบคุณ Martin สำหรับคำตอบที่รวดเร็ว ปัญหาของฉันคือฉันต้องการผลลัพธ์ที่แม่นยำมากดังนั้นฉันคิดว่าฟังก์ชั่นนี้จะไม่ช่วยฉันที่นี่! แต่ขอบคุณสำหรับคำแนะนำ
Sara

0

ขึ้นอยู่กับ postgres และ / หรือความเชี่ยวชาญของ sql คุณมีหลายตัวเลือก:

  1. วิเคราะห์แบบสอบถามผ่านคำสั่งอธิบายเพื่อตรวจสอบว่าคุณกำลังกดปุ่มคอขวดเฉพาะ คำเตือน: บางครั้งผลลัพธ์ของ EXPLAIN อาจเข้าใจยาก

  2. หากคุณคาดหวังว่าส่วนใหญ่หรือส่วนที่สำคัญของรูปทรงเรขาคณิตในตารางที่ 1 ไม่ได้ตัดหลายรูปหลายเหลี่ยมคุณสามารถลองใช้เงื่อนไขเบื้องต้นกับรูปหลายเหลี่ยมที่ง่ายกว่า (เช่นโดยการแบ่งรูปหลายเหลี่ยมในชิ้นเล็ก ๆ ) จากนั้นเรียกใช้ ผลลัพธ์เหล่านั้น ดูตัวอย่างด้านล่าง

  3. และถ้าหาก CPU เป็นคอขวด (เช่นเซิร์ฟเวอร์เป็นทางแยกคอมพิวเตอร์ติด) ฉันไม่เป็นเรื่องแนะนำให้คุณได้รับที่ใหญ่กว่า, เร็วกว่า, CPU มีประสิทธิภาพมากขึ้นหรือให้เช่าเพียงครั้งเดียวสูง CPU อินสแตนซ์ปิดของ Amazon EC2 และทำลายมันเมื่อคุณอยู่ เสร็จแล้ว

ตัวอย่างแบบสอบถามสำหรับรายการ 2:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

เพื่อปรับปรุงประสิทธิภาพการทำงานคุณสามารถทำให้ตัวเลือกย่อยst1เป็นตารางชั่วคราวเพื่อให้คุณสามารถจัดทำดัชนีได้

@Nicklas มีสิทธิ์ชี้ให้เห็นในความคิดเห็นที่ตัวอย่างสำหรับข้อเสนอแนะ 2 ไม่ควรช่วย เขาพูดถูก แต่ฉันคิดว่าฉันเองก็เป็นส่วนหนึ่งเช่นกัน

ในความเป็นจริงดูเหมือนว่าคำถามที่คล้ายกันถูกถาม (และตอบ) เมื่อเดือนพฤศจิกายนที่ผ่านมาบน postgis ML:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

และเปลี่ยนคำแนะนำคือการแบ่งรูปหลายเหลี่ยมเพื่อให้ดัชนีสามารถกรองการแยกที่ผิดพลาดได้อย่างมีประสิทธิภาพมากที่สุดซึ่งจะถูกเรียกใช้โดยการตรวจสอบขอบเขตอย่างง่าย


ข้อเสนอแนะ 2 ไม่ควรช่วยเพราะนั่นคือสิ่งที่ดัชนีกำลังทำอยู่ ดังนั้นสิ่งก่อสร้างนั้นก็จะทำเหมือนเดิมอีกครั้ง
Nicklas Avén

@ NicklasAvénถูกต้องฉันแก้ไขคำตอบแล้ว
unicoletti

0

การใช้ ST_SubDivide()

สำหรับ Postgis เวอร์ชั่น 2.2 คุณสามารถST_SubDivideใช้ได้

ST_Subdivide - ส่งคืนชุดของรูปทรงเรขาคณิตที่ไม่มีรูปทรงเรขาคณิตในชุดมีจำนวนจุดยอดเกินกว่าที่ระบุ

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

คุณยังสามารถ

  • ใช้ตารางชั่วคราว
  • ดัชนี

ที่นี่เราใช้ST_SubDivideเพื่อแยกรูปหลายเหลี่ยมออกเป็น subpolygons ที่มีจุดยอด 10 หรือน้อยกว่า

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

แล้วก็

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

อย่าทำข้างต้นมันจะแนะนำข้อผิดพลาดในการปัดเศษ

การปรับทั่วไป

ดูที่หัวข้อเคล็ดลับประสิทธิภาพในเอกสารด้วย ตรวจสอบให้แน่ใจว่าคุณได้รับการปรับอย่างเหมาะสม พิจารณาการเพิ่มmax_parallel_workers_per_gatherเพื่อใช้ประโยชน์จากการขนาน (ปัจจุบันเป็นค่าเริ่มต้นเป็น off)

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