STIntersects의 성능 향상


11

테이블 T_PIN에는 300,000 개의 핀과 T_POLYGON36,000 개의 다각형이 있습니다. T_PIN이 색인이 있습니다 :

CREATE SPATIAL INDEX [T_PIN_COORD] ON [dbo].[T_PIN]
(
[Coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];

T_POLYGON 있다 :

CREATE SPATIAL INDEX [T_POLYGON_COORD] ON [dbo].[T_POLYGON]
(
[COORD]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY];

쿼리는의 교차점을 찾을 수 T_PINT_POLYGON실행하는 데 45 분 이상 소요 :

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;

결과는 4,438,318 행입니다.

이 쿼리를 어떻게 가속화 할 수 있습니까?


`T_POLYGON.Coord.STIntersects (T_PIN.COORD) = 1 '을 사용해 보셨습니까?
트래비스

쿼리 계획을보고 싶습니다. Postgres에서 작업하지만 비슷한 쿼리를 실행해야하지만 상당히 큰 데이터 세트에서 실행해야합니다. 최악의 것들을 약 2 일 (불행히도 스크립팅 포함)으로 낮추는 기술을 생각해 냈지만 쿼리 계획을 먼저 보려고합니다.
John Powell

내 두 테이블의 다각형을 곱하면 조합의 잠재적 교차점 수와 비교하여 7000 배 더 많은 수를 가지게되므로 이틀간 내 이틀이 꽤 좋아 보인다고 생각합니다. 그러나 쿼리 계획을 보지 않고 다각형 당 평균 점 수에 대해 알지 못하면 구체적인 솔루션을 찾기가 어렵습니다.
존 파월

답변:


7

먼저, 쿼리 실행 계획을보고 공간 인덱스가 사용되고 있는지 확인하고 공간적 인덱스 검색 (공간) 항목이 있는지 확인하십시오.

사용중인 것으로 가정하면 단순화 된 다각형이있는 경계 상자를 기반으로 보조 / 단순화 필터를 추가하여 먼저 확인할 수 있습니다. 그런 다음 이러한 단순화 된 다각형과의 일치를 기본 필터를 통해 실행하여 최종 결과를 얻을 수 있습니다.

1) 새로운 지리 및 기하학 열을 [dbo]. [T_POLYGON] 테이블에 추가하십시오.

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;

2) 바운딩 박스 폴리곤 생성 (STEnvelope ()을 활용하기 위해 형상을 초기 변환하는 과정) :

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
    COORD.STAsBinary(), COORD.STSrid).STEnvelope();

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
    SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);

3) 단순화 된 지리 열에 공간 인덱스 작성

4)이 단순화 된 지리 열에 대한 교차점을 얻은 다음 일치하는 지리 데이터 유형을 다시 필터링하십시오. 대략 다음과 같습니다.

;WITH cte AS
(
   SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
    AND T_PIN.pinID IN (SELECT pinID FROM cte)
    AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)

편집 : (1) 및 (2)를이 계산 된 지속 열로 바꿀 수 있습니다. 제안에 대한 폴 화이트에게 신용.

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS  ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED

그래, 그게 내가 받고있는 것입니다. 넓은 범위의 영역을 가진 두 테이블 세트를 공간적으로 "결합"할 때 발견 한 문제는 최적화 프로그램이 종종 다각형 테스트에서 두 번의 전체 테이블 스캔과 많은로드 포인트를 수행한다는 것입니다.
John Powell

2

이와 같은 쿼리는 다각형의 복잡성으로 인해 종종 오랜 시간이 걸립니다. 복잡한 해안선 (예를 들어)이 경계 근처에있는 지점을 테스트하는 데 오랜 시간이 걸리며 지점이 내부 또는 외부에 있는지 확인하기 위해 여러 수준을 확대해야합니다.

... 여러분이 .Reduce()도움이되는지 확인하기 위해 다각형을 시도해 볼 수 있습니다.

이 기능에 대한 자세한 내용은 http://msdn.microsoft.com/en-us/library/cc627410.aspx 를 참조 하십시오.


1

Microsoft 문서에 따르면 공간 인덱스는 WHERE절 과 함께 비교 술어의 시작 부분에 나타날 때 다음 방법에서 지리 유형과 함께 사용됩니다 .

  • STIntersects
  • STDistance
  • STEquals

지오메트리 유형의 메서드 (제한된 목록) 만의 공간 인덱스 사용을 트리거 JOIN ... ON하므로 사용하도록 코드를 변경 WHERE geog1.STIntersects(geog2) = 1하면 속도가 향상됩니다.

또한 g2server의 답변에 조언을 하고 필터링하고 공간 인덱스를 추가하기 위해 다음을 추가하는 것이 좋습니다.

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
     ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
                                                           [COORD].[STSrid])
                 .STEnvelope().STAsBinary(),(4326))) PERSISTED

그런 다음 다음과 같은 쿼리를 가질 수 있습니다 (이 게시물을 빨리 작성했지만 아직 테스트하지 않았습니다. 이는 귀하의 쿼리와 가장 높은 답변이 JOIN ON 공간 op = 1을 사용하므로 공간 인덱스) :

SELECT   
     (SELECT p2.polygon_id
      FROM   T_Polygon p2
      WHERE  p2.coords.STIntersects(t.coords) = 1),
     t.pin_id
FROM     T_PIN t
WHERE    
     (SELECT t.coords.STIntersects(p.coords)
      FROM   T_POLYGON p
      WHERE  t.coords.STIntersects(p.SimplePolysGeog) = 1) = 1

참고 : 위의 결과는 SimplePolysGeog겹치는 경우 작동하지 않습니다 (핀에서 두 개의 단순화 된 Geog에있을 수 있음). 하위 쿼리가 둘 이상의 결과를 반환 한 경우 오류가 발생합니다.

MS Docs의 공간 인덱스 개요에서 :

공간 인덱스가 지원하는 지리 방법

특정 조건에서 공간 인덱스는 STIntersects (), STquals () 및 STDistance ()와 같은 집합 지향 지리 메서드를 지원합니다. 공간 인덱스에서 지원하려면 이러한 메소드는 쿼리의 WHERE 절 내에서 사용해야하며 다음과 같은 일반적인 형식의 술어 내에서 발생해야합니다.

geography1.method_name (geography2) 비교 _ 연산자 valid_number

널이 아닌 결과를 리턴하려면 geography1geography2 에 동일한 SRID (Spatial Reference Identifier) 가 있어야합니다 . 그렇지 않으면, 메소드는 NULL을 리턴합니다.

공간 인덱스는 다음 술어 양식을 지원합니다.


공간 인덱스를 사용하는 쿼리

공간 인덱스는 WHERE 절에 인덱스 공간 연산자가 포함 된 쿼리에서만 지원됩니다. 예를 들어 다음과 같은 구문 :

[spatial object].SpatialMethod([reference spatial object]) [ = | < ] [const literal or variable]

쿼리 옵티마이 저는 공간 연산의 공통성을 이해합니다 @a.STIntersects(@b) = @b.STInterestcs(@a). 그러나 비교 시작에 공간 연산자가 포함되어 있지 않으면 공간 인덱스가 사용되지 않습니다 (예 : WHERE 1 = spatial op공간 인덱스를 사용하지 않음). 공간 인덱스를 사용하려면 비교를 다시 작성하십시오 (예 :) WHERE spatial op = 1.

...

SimplePolysGeogs겹치는 경우 다음 쿼리가 작동합니다 .

;WITH cte AS
(
   SELECT T_PIN.PIN_ID, 
          T_POLYGON.POLYGON_ID, 
          T_POLYGON.COORD 
   FROM T_PIN 
   INNER JOIN T_POLYGON
   ON T_PIN.COORD.STIntersects(T_POLYGON.SimplePolysGeog) = 1
)

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN cte
ON T_PIN_PIN_ID = cte.PIN_ID
where cte.[COORD].STIntersects(T_PIN.COORD) = 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.