2011-08-09 87 views
6

我正在生成含有大量預先存在的Access數據庫中的數據報告(〜以後緊湊&修復500 MB),和我有一個緩慢的子查詢的麻煩。很慢的子查詢

該數據庫有一個大表,包含了每一位顧客的購買記錄。這是一個簡單的查詢,它可以查找購買了藍色小部件的客戶。它在幾秒鐘內完成並返回大約一萬條記錄。

SELECT DISTINCT CustomerId 
FROM ProductSales 
WHERE Product = 'BLUE' 

下面是一個查詢,它試圖找到購買了藍色小部件但不是紅色小部件的客戶。大約需要一個小時才能運行。

SELECT DISTINCT CustomerId FROM ProductSales 
WHERE Product = 'BLUE' 
AND CustomerId NOT IN (
    SELECT CustomerId 
    FROM ProductSales 
    WHERE Product = 'RED' 
) 

有沒有辦法重構第二個查詢,使其花費幾分鐘而不是一個小時?

+0

我相信客戶ID字段上有索引兩個表中? –

+0

你試過SELECT DISTINCT客戶編號FROM ProductSales WHERE產品= 'BLUE' 減SELECT客戶編號FROM ProductSales WHERE產品= '紅'。我已經看到它真正加快了查詢的情況,但情況因人而異 –

+0

@Marc B:這裏有只有一個表,但客戶ID被索引就可以了。 – James

回答

10

訪問數據庫引擎不能使用索引Not In,所以它肯定會很慢。通過CustomerId上的索引,該查詢應該快得多,因爲數據庫引擎可以使用該索引。

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

Woah。從60分鐘降到大約一秒鐘。這比舊版本快3600倍。謝謝! :-)爲了將來的參考,是否有一個SQL操作列表Access不在某處使用索引? – James

+1

這裏可能有一個列表,但我不知道在哪裏。 :-)如果你想堅持這一點,Google Jet ShowPlan ...將權威地告訴你數據庫引擎如何在你的查詢中使用索引。你可以在這裏找到關於查詢性能的詳細討論:http://msdn.microsoft.com/en-us/library/aa188211(office.10).aspx – HansUp

+1

這不是沒有在和不存在從不使用索引 - 它是你無法預測他們什麼時候會,什麼時候不會。任何時候你都可以將一個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