2012-01-31 2 views
1

내 데이터베이스에는 zipcode 정보 (필자는 lon/lat 좌표로 묶여 있음)가있는 미국 전역에 약 2,000 개의 위치가 흩어져있는 디렉터리가 있습니다.SQL 교차 적용 성능 문제

나는 또한 내가 이웃 위치를 얻기 위해 노력하고 각각의 위치는 (검색 같은 우편 번호 제외)

를 우편 번호 이웃의 목록을 반환하는 두 개의 매개 변수 (우편 번호 & 마일) 소요 테이블 기능이 ids. 위치 # 4 세 근처 위치를 갖는다면, 출력 보일 ​​것 같은

  1. 4 5
  2. 4 24
  3. 4 (137) 인

, 위치 5, 24, 137 다음과 같이 내가 원래 크로스 내 기능을 적용 사용하려 4.

위치의 X 마일 이내 :

SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A 
CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist(A.Sl_Zip,7))) AS Q 
WHERE A.SL_StoreNum='04' 

그러나 결과는 20 분 넘게 실행되어 취소되었습니다. 나는 우편 번호에 하드 코딩 시도했고, 즉시 목록

SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A 
CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist('12345',7))) AS Q 
WHERE A.SL_StoreNum='04' 

인근 지역의 목록을 달성하는 가장 효율적인 방법은 무엇입니까 반환? 여기서 "04"를 예로 들었을 때 2,000 개 지점에 대한 분석을 실행하고 싶습니다.

"udf_GetLongLatDist"는 몇 가지 수학을 사용하여 두 지리 좌표 간의 거리를 계산하고 거리가 0보다 큰 우편 코드 목록을 반환하는 함수입니다.

+0

귀하의 질문과 직접적인 관련이없는 쪽 댓글이지만, 우편 번호에 대한 무게 중심 위도/경도 위치는 종종 시골 우편 번호 일 때 대부분의 사람들이 거주하는 우편 번호 내의 위치와 상당히 멀리 떨어져있었습니다. 그래서 우리는 zipcode와 관련된 주요 도시/도시의 위도/경도와 위도/경도의 두 위치를 사용했습니다. 이 두 위치 중 하나가 대상 위치의 x 마일 내에있는 경우 우편 번호가 가까이있는 것으로 간주되었습니다. – hatchet

답변

0

기타 답변은 알고리즘을 다시 적용하는 것입니다. 나는 개인적으로 모든 우편 번호의 미리 계산 된지도를 서로에 조언한다. 코드 변경을 최소화하기 위해 기존 udf에 이러한 최적화를 포함 할 수 있어야합니다.

그러나 리팩토링 쿼리는 다음과 같을 수 있습니다.

SELECT 
    A.SL_STORENUM, A.Sl_Zip, C.SL_STORENUM 
FROM 
    tbl_store_locations     AS A 
CROSS APPLY 
    dbo.udf_GetLongLatDist(A.Sl_Zip,7) AS B 
INNER JOIN 
    tbl_store_locations     AS C 
    ON C.SL_Zip = B.zipnum 
WHERE 
    A.SL_StoreNum='04' 

또한, CROSS의 성능을 사용하면 UDF가 다중 문보다는 INLINE 있는지 확인 할 수 있다면 큰 도움이됩니다 적용됩니다. 이렇게하면 udf가 훨씬 깨끗한 실행 계획을 위해 인라인 (매크로와 유사)으로 확장 될 수 있습니다.

이렇게하면 udf에서 추가 필드를 반환 할 수도 있습니다. 그런 다음 옵티마이 저는 실제로 필드를 사용하는지 여부에 따라 계획에서 해당 필드를 포함 시키거나 제외시킬 수 있습니다. 이러한 예는 udf의 쿼리에서 쉽게 액세스 할 수있는 경우 SL_StoreNum을 포함하는 것이므로 마지막 참여의 필요성을 제거하십시오.

+0

이것은 잘 작동했습니다! 그것은 약 90 초 만에 모든 위치를 달렸다. 당신이 당신의 업적이 내 직업보다 훨씬 나은 이유를 설명해 주시겠습니까? 또한 udf가 어떻게 구성되어 있는지 살펴볼 것입니다. – ElPresidente

+0

@ user1181412 - 기본 차이점은 당신이 'IN'을 사용하고, 내 것이'JOIN'을 사용한다는 것입니다. 그리고 그 광산은 메인 테이블과 같은 범위에서 함수 호출을 유지했습니다. 필자는 이것이 옵티마이 저가 관계에 대한 명확한 시각을 갖고 더 나은 계획을 수립했다는 것을 의미합니다. 특히 udf가 이미 InLine 인 경우 세트로 한 번 실행했을 가능성이 있습니다. – MatBailie

1

이 기능을 사용할 때 각 행에 가능한 모든 거리를 계산해야 할 것입니다. 그것이 그렇게 오래 걸리는 이유입니다. 실제 물리적 위치는 실제 이동하지 않으며, 일반적으로 이동하면 각 우편 번호에서 다른 모든 우편 번호까지의 거리를 미리 계산합니다 (새 우편 번호를 추가 할 때 한 달에 한 번만 업데이트). 거리가 미리 계산되면, 당신이 할 일은

select zip2 from zipprecalc where zip1 = '12345' and distance <=10 
+0

감사합니다. 사실 미리 컴파일 된 목록을 만드는 것이 내 목표 였기 때문에 주기적으로 업데이트해야했습니다. 아래 사람이 내 것보다 훨씬 빠르게 실행되는 쿼리를 게시했습니다. – ElPresidente

1

우리는 비슷한 뭔가를 만 위도 한정된 범위 내에 다른 된 우편 번호의 거리를 계산하여 최적화와 같은 쿼리를 실행합니다. 당신이 @miles 내의 다른 지퍼를 원한다면, 당신은 그럼 당신은 다른 우편 번호 행의 아주 작은 부분 집합의 대권 거리를 계산됩니다

where latitude >= @targetLat - (@miles/69.2) and latitude <= @targetLat + (@miles/69.2) 

를 사용합니다. 우리는 미리 계산할 필요가 없도록 우리의 사용에서 이것을 충분히 빨리 발견했습니다.

위도와 경도가 어떤 거리인지를 나타내는 적도와 극 사이의 유사도 때문에 경도에 대해 동일한 작업을 수행 할 수 없습니다.