st_intersects가 &&보다 빠른 이유


10

포인트 테이블입니다. ~ 1M 기록

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

끝난. 나는 지금 조금 나아졌다
alasarr

새로운 쿼리 계획을 백 포트하려고했습니다. 계획을 자유롭게 업그레이드하되 스타일을 유지하십시오.
Evan Carroll

4
이 질문을 살펴보십시오 . && 연산자는 실제로 바운딩 박스 쿼리를 수행하는 반면 ST_Intersects는 바운딩 박스 쿼리를 사용하여 실제 비교를 테스트 할 지오메트리를 결정하므로 && 더 빠를 것으로 예상됩니다. 그러나 &&의 오른쪽에 ST_MakeEnvelope를 사용하면 쿼리 플래너가 어떤 이유로 든 전체 테이블 스캔을 선택하게되었을 가능성이 있습니다 (설명에서 알 수 있음). CTE에서 먼저 지오메트리를 작성하고 옵티 마이저를 "속일"수 있는지 확인하십시오.
존 파월

네가 옳아! 그것은 CTE 내부에서 작동합니다
alasarr

답변:


16

이러한 종류의 발견은 상당히 자주 발생하며 다소 모호하므로 복원 할 가치가 있습니다. ST_Intersects 또는 && (ST_Intersects가 후드에서 사용하는)와 같이이를 사용하는 함수 내에서 지오메트리를 정의하는 경우 "계획"은 지오메트리 작성 결과를 알 수 없으므로 쿼리 플래너가 전체 테이블 스캔을 선택합니다. 함수, 즉 ST_MakeEnvelope (이 경우 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는 비트 맵 스캔 (gist가 아닌) 인덱스를 사용하는 반면 &&는 인덱스를 사용하지 않습니다. 따라서 두 쿼리 모두 CTE를 사용하면 더 빠르지 만 이제 &&는 ST_Intersects보다 빠릅니다.

이 질문 에서 무슨 일이 일어나고 있는지에 대한 더 많은 설명 있습니다.

편집 : 이것을 명시 적으로 표현하기 위해 postgis.sql ( CREATE EXTENSION postgisPostgres 설치의 contrib 디렉토리에서 호출되고 발견 됨)에서 ST_Intersects 정의를 보면 다음과 같이 표시됩니다.

---- 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에서 함수가 정의되어 있고 더 명확해야합니다.
존 파월
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.