2010-12-28 3 views
1

다음과 같은 쿼리를 실행하려면 어떻게해야합니까? (우리는 연구 최적화를 위해 실행을 중단했지만 우리 중 누구도 DB 전문가가 아닙니다.) 세트 기반 제외를 수행하는 것이 매우 간단해야하는 것처럼 보입니다. 맞습니까?이 쿼리는 서브 쿼리의 합계보다 훨씬 길게 실행되는 이유는 무엇입니까?

SELECT 
    field 
FROM 
    (subquery that returns 1173126 rows in 20 seconds) 
WHERE 
    field NOT IN (subquery that returns 3927646 rows in 69 seconds) 

이 정보에 도움이 될만한 정보가 있으면 어떻게해야합니까?

는 (실제 쿼리는 그것에 대해 위험한 특정 뭔가 문제를 일으키는있을 경우 다음과 같습니다.)

SELECT blob FROM (
     SELECT a.line1 + '|' + substring(a.zip,1,5) as blob 
     FROM registrations r 
     JOIN customers c ON r.custId = c.Id 
     JOIN addresses a ON c.addressId = a.Id 
     WHERE r.purchaseDate > DATEADD(year,-1,getdate()) 
     GROUP BY a.line1 + '|' + substring(a.zip,1,5)) sq 
WHERE blob NOT IN (
     SELECT a.line1 + '|' + substring(a.zip,1,5) as blob 
     FROM registrations r 
     JOIN customers c ON r.custId = c.Id 
     JOIN addresses a ON c.addressId = a.Id 
     WHERE r.purchaseDate BETWEEN DATEADD(year,-5,getdate()) AND DATEADD(year,-1,getdate()) 
     GROUP BY a.line1 + '|' + substring(a.zip,1,5)) 

답변

2

지난 1 년 동안 구매했지만 지난 5 년 이내에 구입하지 않은 주소를 검색하는 것 같습니다.

SELECT DISTINCT a.line1, SUBSTRING(a.zip, 1, 5) 
FROM addresses a 
WHERE id IN 
     (
     SELECT c.addressId 
     FROM customers c 
     JOIN registrations r 
     ON  r.custId = c.id 
     AND  r.purchaseDate > DATEADD(year, -1 ,getdate()) 
     ) 
     AND NOT EXISTS 
     (
     SELECT NULL 
     FROM customers c 
     JOIN registrations r 
     ON  r.custId = c.id 
     JOIN addresses ai 
     ON  ai.id = c.addressId 
     WHERE r.purchaseDate BETWEEN DATEADD(year,-5,getdate()) AND DATEADD(year,-1,getdate()) 
       AND ai.line1 = a.line1 
       AND SUBSTRING(ai.zip, 1, 5) = SUBSTRING(a.zip, 1, 5) 
     ) 

이 쿼리는 다른 ID로 주소에 line1, zip의 중복의 관심. 그런 중복이 있습니까?

+0

예, 우리는 "새로운"고객을 찾고 있으며 중복 된 line1, zip 조합이 ID 위에 있습니다. – clweeks

+0

@clweeks : 같은 주소에서 3 년 전 구매했지만 다른 'id'로 구매 한 경우 새로운 것으로 간주되지 않습니까? – Quassnoi

+0

수정하십시오.세대 중 누군가가 구매했거나 데이터가 잘못 입력되었을 수 있으며 새로운 구매를 한 주소/가구를 찾고 있습니다 ('신규'에는 5 년 전에 구입 한 사람이 포함되지만 그 이후는 포함되지 않음) . – clweeks

2

이 실현되지 않을 수도 있지만, 문에 의해 IF 문으로 변환됩니다 해당 없음 쿼리 엔진. 따라서, 귀하의 예에서는 모든 행 (3.9M)이있는 거대한 IF 문을 작성합니다. 그런 다음 각 IF 조건을 평가하여 값이 존재하는지 확인해야합니다. 16+ 시간이 걸리는 것은 놀라운 일이 아닙니다.

EXISTS 또는 아마도 조인으로 변환하는 방법을 찾는 것이 훨씬 낫습니다.

+0

이것은 각각의 'IF'조건을 평가하지 않거나 모두 빌드합니다. 이를 세미 조인이라고하며이를 실행하기위한 다양한 알고리즘이 있습니다. – Quassnoi

+0

여기에 게시하기 전에 실행 계획 (실제로 사용법을 알지는 못했지만)을 찾아 내서 "Left Anti Semi Join"을 찾았습니다. 그러나 내가하고 싶은 모든 것을 읽을 시간을 찾는 것이 너무 힘들다. – clweeks

+0

@Quassnoi - 수정 해줘서 고마워. 내 이해 IF 문을 만든 것입니다. 행 수가 적 으면 더 많은 수의 행에 대해 세미 조인을 수행합니까? –

1

두 번째 하위 쿼리는 첫 번째 하위 쿼리의 각 행에 대해 한 번 실행됩니다. 당신은 당신의 실제 쿼리, 가장 좋은 방법을 추가

즉, 예상 완료 시간이 주위에있을 것입니다 (1,173,126 * 69) = 8천94만5천3백94초

약 154년입니다

...

후 인덱스를 테이블에 추가하여 두 개의 쿼리를 최적화하는 것이 좋습니다. 추가 할 색인을 정확히 말할 수는 없지만 표에 대한 올바른 색인을 선택하는 데 유용한 자료가 많이 있습니다.

+0

이것은 어떻게 작동하지 않습니다. – Quassnoi

관련 문제