ทำไม st_intersects เร็วกว่า &&


10

มันเป็นตารางคะแนน ~ 1 ล้านระเบียน

SELECT COUNT(*) as value FROM alasarr_social_mv s; 
Output: 976270

ดูเหมือนว่า st_intersects บังคับให้ใช้ดัชนีเชิงพื้นที่ แต่ && ไม่

ตัวอย่างการใช้ST_Intersects(282ms)

SELECT COUNT(*) as value
FROM alasarr_social_mv 
WHERE ST_Intersects(
  the_geom_webmercator, 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)
)


Aggregate  (cost=34370.18..34370.19 rows=1 width=0) (actual time=282.715..282.715 rows=1 loops=1)
  ->  Bitmap Heap Scan on alasarr_social_mv s  (cost=5572.17..34339.84 rows=60683 width=0) (actual time=21.574..240.195 rows=178010 loops=1)
        Recheck Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Filter: _st_intersects(the_geom_webmercator, '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Heap Blocks: exact=4848
        ->  Bitmap Index Scan on alasarr_social_mv_gix  (cost=0.00..5569.13 rows=182050 width=0) (actual time=20.836..20.836 rows=178010 loops=1)
              Index Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
Planning time: 0.192 ms
Execution time: 282.758 ms

ตัวอย่างการใช้&&(414ms)

SELECT COUNT(*) as value
FROM alasarr_social_mv  
WHERE the_geom_webmercator && 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)

Aggregate  (cost=22535.97..22535.97 rows=1 width=0) (actual time=414.314..414.314 rows=1 loops=1)
  ->  Seq Scan on alasarr_social_mv  (cost=0.00..22444.94 rows=182050 width=0) (actual time=0.017..378.427 rows=178010 loops=1)
        Filter: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Rows Removed by Filter: 798260
Planning time: 0.134 ms
Execution time: 414.343 ms

รุ่น PostGIS

POSTGIS="2.2.2" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.0, released 2014/04/16" LIBXML="2.7.8" LIBJSON="UNKNOWN" (core procs from "2.2.2" need upgrade) RASTER (raster procs from "2.2.2" need upgrade)  alasarr 2 mins ago

2
อย่าวางภาพหน้าจอของข้อความลงในคำถาม คุณสามารถคัดลอกและวางสิ่งเหล่านั้นเป็นรหัสได้หรือไม่? ฉันอ่านมันไม่ได้เพื่อช่วยคุณ
Evan Carroll

เสร็จสิ้น ฉันคิดว่าดีขึ้นเล็กน้อยในตอนนี้
2560

ฉันพยายาม backport แผนการสืบค้นใหม่ของคุณ อย่าลังเลที่จะอัพเกรดแผน แต่พยายามรักษาสไตล์ไว้
Evan Carroll

4
ลองดูที่คำถามนี้ ตัวดำเนินการ && ทำการสอบถามกล่องที่มีขอบเขตในขณะที่ ST_Intersects ใช้แบบสอบถามในกล่องที่มีขอบเขตเพื่อกำหนดรูปทรงที่จะทดสอบสำหรับการเปรียบเทียบที่แท้จริงดังนั้นคุณคาดหวังว่าจะ && เร็วขึ้น อย่างไรก็ตามมีโอกาสที่การใช้ ST_MakeEnvelope ทางด้านขวาของ && กำลังทำให้ตัววางแผนคิวรีเลือกสแกนตารางเต็มด้วยเหตุผลบางประการ (ดังที่เห็นได้จากคำอธิบาย) ลองสร้างเรขาคณิตก่อนเป็น CTE และดูว่าคุณสามารถ "หลอก" เครื่องมือเพิ่มประสิทธิภาพได้หรือไม่
John Powell

คุณถูก! มันทำงานได้ใน CTE
alasarr

คำตอบ:


16

การค้นพบแบบนี้เกิดขึ้นค่อนข้างบ่อยและมันค่อนข้างคลุมเครือดังนั้นจึงควรค่าแก่การพักผ่อน หากคุณกำหนดรูปทรงเรขาคณิตภายในฟังก์ชั่นที่ใช้งานเช่น ST_Intersects หรือ && (ซึ่ง ST_Intersects ใช้ภายใต้ประทุน) ดังนั้นตัววางแผนแบบสอบถามจึงเลือกใช้การสแกนแบบเต็มตารางเนื่องจาก "มัน" ไม่มีความรู้เกี่ยวกับผลลัพธ์ของการสร้างรูปทรงเรขาคณิต ฟังก์ชั่นเช่นST_MakeEnvelopeในกรณีนี้ .. หากคุณกำหนดรูปทรงเรขาคณิตที่คุณต้องการตรวจสอบจุดตัดใน CTE เครื่องมือเพิ่มประสิทธิภาพจะจัดการกับปริมาณที่รู้จักและจะใช้ดัชนีเชิงพื้นที่ถ้ามี

ดังนั้นเขียนแบบสอบถามของคุณใหม่เป็น:

WITH test_geom (geom) AS 
   (SELECT ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857))
  SELECT COUNT(*) as value
    FROM alasarr_social_mv mv, test_geom tg 
   WHERE ST_Intersects(mv.the_geom_webmercator, tg.geom)

จะใช้ดัชนีเชิงพื้นที่ ในขณะเดียวกัน && จะใช้ดัชนีเพื่อตรวจสอบกล่องขอบและ (ในขณะที่ฉันไม่สามารถทดสอบข้อมูลของคุณ) ได้ควรเร็วกว่า ST_Intersects

น่าสนใจในข้อความค้นหาของคุณ ST_Intersects ใช้ดัชนีสแกนบิตแมป (ไม่ใช่ส่วนสำคัญ) ในขณะที่ && ไม่มีการใช้ดัชนี ดังนั้นข้อความค้นหาทั้งสองจะเร็วกว่าด้วย CTE แต่ตอนนี้ &&& ควรเร็วกว่า ST_Intersects

มีคำอธิบายเพิ่มเติมของสิ่งที่เกิดขึ้นคือคำถามนี้และคำตอบของมัน / ความคิดเห็น

แก้ไข : เพื่อให้ชัดเจนถ้าคุณดูคำจำกัดความของ ST_Intersects ในpostgis.sql (ซึ่งถูกเรียกโดยCREATE EXTENSION postgisและพบได้ในไดเรกทอรี contrib ของการติดตั้ง Postgres ของคุณ) คุณจะเห็น:

---- Inlines index magic
CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
    RETURNS boolean
    AS 'SELECT $1 OPERATOR(&&) $2 AND _ST_Intersects($1,$2)'
    LANGUAGE 'sql' IMMUTABLE ;

รวมถึงความคิดเห็นที่: มายากลดัชนีอินไลน์


1
ฉันไม่คิดว่า ST_Intersects ใช้ && ภายใต้ประทุน
Evan Carroll

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