2011-08-09 2 views
6

큰 기존 Access 데이터베이스 (~ 012 메가 바이트 ~ 수리 후 ~ 500MB)에 포함 된 데이터에 대한 보고서를 생성하고 있으며 느린 하위 쿼리에 문제가 있습니다. ."NOT IN"을 사용할 때 매우 느린 하위 쿼리

데이터베이스에는 모든 고객 구매 기록이있는 큰 테이블이 있습니다. 다음은 파란색 위젯을 구입 한 고객을 찾는 간단한 쿼리입니다. 몇 초 내에 완료되고 약 1 만 개의 레코드가 반환됩니다.

SELECT DISTINCT CustomerId 
FROM ProductSales 
WHERE Product = 'BLUE' 

파란색 위젯을 구입했지만 빨간색 위젯을 구입 한 고객을 찾으려는 검색어입니다. 달리는 데는 한 시간 정도 걸립니다.

두 번째 쿼리를 리팩토링하여 한 시간이 아닌 몇 분이 걸리는 방법이 있습니까?

+0

CustomerId 필드에 두 테이블의 인덱스가 있다고 가정합니까? –

+0

시도해 보셨습니까? 선택 DISTINCT CustomerId FROM ProductSales WHERE Product = 'BLUE'SELECT CustomerId FROM ProductSales WHERE Product = 'RED'. 나는 쿼리가 실제로 속도를 높이는 경우를 보았지만 YMMV –

+0

@Marc B : 여기에는 표가 하나 뿐이지 만 CustomerId는 색인이 생성됩니다. – James

답변

10

액세스 '데이터베이스 엔진은 Not In에 대한 인덱스를 사용할 수 없습니다. CustomerId에 대한 인덱스를 사용하면 db 엔진이 인덱스를 사용할 수 있기 때문에이 쿼리가 훨씬 빨라야합니다.

SELECT DISTINCT blue.CustomerId 
FROM 
    ProductSales AS blue 
    LEFT JOIN 
     (
      SELECT CustomerId 
      FROM ProductSales 
      WHERE Product = 'RED' 
     ) AS red 
    ON blue.CustomerId = red.CustomerId 
WHERE 
     blue.Product = 'BLUE' 
    AND red.CustomerId Is Null; 

당신은 아마 또한 Not Exists 접근 방법을 시도 할 수 있지만 인덱스 사용은이 보장되지 않습니다. 또한 성능 영향을 자세히 설명하는 David Fenton의 아래 의견을 참조하십시오.

+1

와우. 60 분에서 1 초 정도. 이는 구 버전보다 3600 배 빠릅니다. 감사! :-) 나중에 참조 할 수 있도록 SQL 작업 목록이 있습니까? 액세스는 어딘가에서 색인을 사용하지 않습니까? – James

+1

아마도 어딘가에 목록이있을 것입니다. 그러나 나는 어디 있는지 모르겠습니다. :-) 당신이 하드 코어에 가고 싶다면 Google Jet ShowPlan ...은 db 엔진이 쿼리에 인덱스를 사용하는 방법을 권위있게 알려줍니다. 쿼리 성능에 대한 자세한 설명은 http://msdn.microsoft.com/ko-kr/library/aa188211(office.10).aspx – HansUp

+1

에서 볼 수 있습니다. NOT IN and NOT EXISTS는 인덱스를 사용하지 않습니다. 언제, 언제 할 것인지 예측할 수는 없습니다. NOT IN/EXISTS 하위 쿼리를 JOIN에 다시 엔지니어링 할 수 있으면 언제든지 성능을 향상시킬 수 있습니다. 그러나 결과 집합의 편집 가능성에 따라 달라집니다. JOIN에 사용되는 일부 하위 쿼리는 쿼리를 업데이트 할 수 없도록 만듭니다. –

0

색인이없는 경우 색인을 추가하십시오. 그게 문제라면, RED가 아닌 BLUE가 아닌 많은 주문을하는 고객이 많다는 것입니다. 이 (테스트되지 않은) 쿼리는이를 수정하려고합니다. 이 느릴 수밖에 그래서

SELECT DISTINCT CustomerId FROM ProductSales 
LEFT JOIN (
    SELECT DISTINCT CustomerId cid FROM ProductSales 
    LEFT JOIN (
    SELECT DISTINCT CustomerId 
    FROM ProductSales 
    WHERE Product = 'BLUE' 
) foo ON CustomerId = cid 
    WHERE Product = 'RED' 
) bar USING (CustomerId) 
WHERE cid IS NULL