공간 함수를 통한 행 제한


9

아래 쿼리의 성능을 개선하려고합니다. 쿼리를 작성하는 방법 (FROM 절의 하위 쿼리, WHERE 절의 하위 쿼리)에 상관없이 postgres는 county = 24 인 60 개의 행만 있어도 고가의 ST_DWITHIN 함수를 통해 ~ 570K 행을 모두 실행해야합니다. postgis func을 통해 실행하기 전에 postgres가 county = 24를 필터링하도록하려면 어떻게해야합니까? 700ms는 너무 많은 우려의 원인은 아니지만이 표가 10M +로 증가함에 따라 성능이 걱정됩니다.

또한 p.id는 기본 키이고, p.zipcode는 fk 인덱스이고, z.county는 fk 인덱스이며, p.geom에는 GiST 인덱스가 있습니다.

질문:

EXPLAIN ANALYZE
  SELECT count(p.id)
  FROM point AS p
  LEFT JOIN zipcode AS z
    ON p.zipcode = z.zipcode
  WHERE z.county = 24
    AND ST_DWithin(
      p.geom, 
      ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269), 
      16090.0,
      false
    )

설명 분석 :

Aggregate  (cost=250851.91..250851.92 rows=1 width=4) (actual time=724.007..724.007 rows=1 loops=1)
  ->  Hash Join  (cost=152.05..250851.34 rows=228 width=4) (actual time=0.359..723.996 rows=51 loops=1)
        Hash Cond: ((p.zipcode)::text = (z.zipcode)::text)
        ->  Seq Scan on point p  (cost=0.00..250669.12 rows=7437 width=10) (actual time=0.258..723.867 rows=63 loops=1)
              Filter: (((geom)::geography && '0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography) AND ('0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography && _st_expand((geom)::geography, 16090::double precision)) AND _st_dwithin((g (...)
              Rows Removed by Filter: 557731
        ->  Hash  (cost=151.38..151.38 rows=54 width=6) (actual time=0.095..0.095 rows=54 loops=1)
              Buckets: 1024  Batches: 1  Memory Usage: 3kB
              ->  Bitmap Heap Scan on zipcode z  (cost=4.70..151.38 rows=54 width=6) (actual time=0.023..0.079 rows=54 loops=1)
                    Recheck Cond: (county = 24)
                    Heap Blocks: exact=39
                    ->  Bitmap Index Scan on fki_zipcode_county_foreign_key  (cost=0.00..4.68 rows=54 width=0) (actual time=0.016..0.016 rows=54 loops=1)
                          Index Cond: (county = 24)
Planning time: 0.504 ms
Execution time: 724.064 ms

"p left join zipcode as z"를 "p left join as point (SELECT * FROM zipcode WHERE zipcode.county = 24) as z"와 같은 줄로 변경해보십시오.
weiji14

같은 결과를 시도했습니다. pointcounty = 24 인 ~ 60 행을 새 테이블에 모두 복사하면 쿼리가 724와 비교하여 .453ms 만 걸리므로 큰 차이가 있습니다.
Josh

1
count(*)스타일 문제로 사용해야합니다 . id당신이 말하는 것처럼 pkid 라면 , 그것은 NOT NULL동일하다는 것을 의미합니다. count(id)당신 id이 nullable 경우 해당 질문을해야한다는 단점을 제외하고 .
Evan Carroll

1
왜 왼쪽 외부 조인을 사용하는지 물어볼 수 있습니까? 내부 조인으로 변경해보십시오. 결과는 동일해야합니다
MickyT

z.country가 제한 요인이라면이를 CTE 쿼리에 먼저 넣은 다음 해당 결과와 관심 지점과의 교차점을 확인하는 것이 좋습니다. 이 경우 공간 인덱스가 county = 24보다 덜 선택적이므로 방해가됩니다.
John Powell

답변:


3

예상 행 수와 실제 행 수의 문제점을 확인할 수 있습니다. 플래너는 7,437 개의 행이 있다고 생각하지만 63 개만 있습니다. 통계는 꺼져 있습니다. 흥미롭게도 경계 상자 색인 (색인) 검색을 사용하지 않고 DWithin의 결과를 붙여 넣을 수 있습니다 \d point. PostGIS 및 PostgreSQL의 버전은 무엇입니까?

실행 해보십시오 ANALYZE point. 조건을 위로 올리면 같은 계획이 있습니까?

JOIN zipcode AS z
  ON p.zipcode = z.zipcode
  AND z.county = 24

나는 분석을 실행하고 ON에서 새로운 AND 조건을 시도했지만 여전히 700ms의 실행 시간을 얻었습니다. PGSQL 9.4 및 PostGIS 2.2입니다.
Josh

2

보조 노트로서,이 합리적인 버그를 호출 할 경우이 문제가 PostGIS와 2.3.0에서 수정 될 가능성은.

PostgreSQL문서에서

cpu_operator_cost 단위로 함수의 예상 실행 비용을 제공하는 양수입니다. 함수가 집합을 반환하면 반환 된 행당 비용입니다. 비용을 지정하지 않으면 C 언어 및 내부 기능에 대해 1 단위, 다른 모든 언어에서 기능에 대해서는 100 단위로 가정됩니다. 값이 클수록 플래너는 함수를 필요 이상으로 자주 평가하지 않도록합니다.

따라서 기본 비용은 1 (매우 저렴)이었습니다. D_WithinGIST 지수를 사용하는 것은 매우 저렴합니다. 그러나 내부 프록시를 통해 100으로 증가했습니다 _ST_DWithin.

저는 CTE 방법을 좋아하지 않습니다. CTE는 최적화 펜스입니다. 따라서 이러한 방식으로이를 수행하면 향후 최적화를위한 잠재적 인 공간이 제거됩니다. saner 기본값으로 해결하면 오히려 업그레이드합니다. 하루가 끝나면 우리는 일을 끝내야하며 그 방법이 분명히 효과가 있습니다.


1

John Powell의 힌트 덕분에 with / CTE 쿼리에 카운티 제한 조건을 적용하도록 쿼리를 수정했으며 700에서 222ms로 성능이 약간 향상되었습니다. 데이터가있을 때 얻는 .74ms와는 여전히 큰 차이가 있습니다. 자신의 테이블. 고가의 postgis 기능을 실행하기 전에 플래너가 데이터 세트를 제한하지 않는 이유는 여전히 확실하지 않으며 더 큰 데이터 세트를 사용하려고 시도해야하지만 이것이 현재로서는이 독특한 상황에 대한 해결책 인 것처럼 보입니다.

with points as (
   select p.id, p.geom from point p inner join zipcode z
   on p.zipcode = z.zipcode
   where county = 24
   ) 


SELECT count(points.id)
FROM points
WHERE ST_DWITHIN(points.geom, (ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269)), 16090.0, false)

1
우리는 세 가지 쿼리 계획과 테이블의 스키마 (내 대답 \ d 지점에서 요청)를 모두보아야합니다.
Evan Carroll

0

on on 인덱스를 작성하면 zipcode(county, zipcode)z에서만 인덱스를 스캔 할 수 있습니다.

또한 실험 할 수 있습니다 btree_gist중 하나를 만들 확장 point(zipcode, geom)인덱스 또는 point(geom, zipcode)zipcode(zipcode, county)인덱스를.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.