2011-04-19 225 views
7

我有兩個查詢,它們各自運行得非常快(少於2秒)。但是,當我嘗試將它們作爲子查詢加入時,它運行的速度很慢,速度很慢。上次我跑了它大概需要68秒。以下是完整的查詢:兩個查詢分開執行速度很快,加入子查詢時速度很慢

SELECT t.count, 
     t.total 
    FROM (SELECT t.account_number, 
       COUNT(t.id) count, 
       SUM(t.amount) total, 
       ib.id import_bundle_id 
      FROM import_bundle ib 
      JOIN generic_import gi ON gi.import_bundle_id = ib.id 
      JOIN transaction_import ti ON ti.generic_import_id = gi.id 
      JOIN account_transaction t ON t.transaction_import_id = ti.id 
      JOIN transaction_code tc ON t.transaction_code_id = tc.id 
     WHERE tc.code IN (0, 20, 40) 
     GROUP BY t.account_number) t 
    JOIN (SELECT a.account_number, 
       np.code 
      FROM import_bundle ib 
      JOIN generic_import gi ON gi.import_bundle_id = ib.id 
      JOIN account_import ai ON ai.generic_import_id = gi.id 
      JOIN account a ON a.account_import_id = ai.id 
      JOIN account_northway_product anp ON anp.account_id = a.id 
      JOIN northway_product np ON anp.northway_product_id = np.id 
     WHERE np.code != 'O1') a ON t.account_number = a.account_number 

該查詢應該運行緩慢並不總是令人驚訝。如果這些是兩個單獨的表而不是子查詢,我會在其account_number列上放置索引。但是,顯然不可能將索引放在查詢結果中,所以我不能這樣做。我懷疑這是問題的一部分。

除此之外,我不明白爲什麼查詢速度慢,我沒有任何關於如何加快速度的想法,除了添加兩個彙總表,我不想這樣做,如果我不必。

順便說一句,這個英語查詢可能是「獲取所有POS交易(代碼0,20和40)帳戶不透支保護帳戶(代碼O1)」。

+0

請顯示您的解釋結果和您的表結構 – Neo 2011-04-19 13:43:42

+0

第二個查詢是否可以在'account_number'返回重複項? – Quassnoi 2011-04-19 13:44:31

回答

1

把檢查到主查詢:

SELECT t.account_number, 
     COUNT(t.id) count, 
     SUM(t.amount) total, 
     ib.id import_bundle_id 
FROM transaction_code tc 
JOIN account_transaction t 
ON  t.transaction_code_id = tc.id 
JOIN transaction_import ti 
ON  ti.id = t.transaction_import_id 
JOIN generic_import gi 
ON  gi.id = ti.generic_import_id 
JOIN import_bundle ib 
ON  ib.id = gi.import_bundle_id 
WHERE tc.code IN (0, 20, 40) 
     AND t.account_number NOT IN 
     (
     SELECT anp.id 
     FROM account_northway_product anp 
     JOIN northway_product np 
     ON  np.id = anp.northway_product_id 
     WHERE np.code = '01' 
     ) 
GROUP BY 
     t.account_number 

創建以下指標:

transaction_code (code) 
account_transaction (transaction_code_id) 
account_transaction (account_number) 
+0

令人驚歎!謝謝! – 2011-04-19 13:55:07

0

由於整體的複雜性,MySQL可能會錯誤地優化查詢。

你會發現最好的選擇是分階段運行它。

SELECT * INTO #query1 FROM <query1> 
SELECT * INTO #query2 FROM <query2> 
SELECT * FROM #query1 INNER JOIN #query2 ON <predicate> 


另一個選擇可能是使用提示,雖然我不能在MySQL中熟悉它們。基本上,找出爲每個子查詢單獨生成的計劃,然後強制不同的連接使用NESTED LOOP JOIN,MERGE JOIN等。這限制了優化器可以做什麼,因此得到「錯誤」,但也限制了它的能力隨着數據統計信息的變化而作出響

+0

除了'NESTED LOOPS',MySQL'不能做任何事情。 – Quassnoi 2011-04-19 13:54:14

0

根據我看到你查詢;

1)看起來像你的PK是import_bundle表上的帳號。您需要該列上的聚簇索引 2)在(代碼)northway_product表上添加索引以及在transaction_code表上添加(代碼)也會有所幫助。

0

由於大多數表已經加入,爲什麼再次加入......只需粘貼已設置ID的其他表。另外,因爲所有的JOIN都是JOIN,而且沒有一個是LEFT連接,所以它只暗示所有聯接中都有記錄(因爲原來的查詢最終也加入了結果集)。

此外,通過添加AND np.code!='01',它將立即排除這些條目,從而只在您的查詢中使用這些條目。所以這個內部的「PreQuery」(別名PQ)爲你做所有的工作。但是,您的羣組不會包含導入包ID,並可能通過對您的錯誤回答進行提供。根據需要調整。然後,結果是隻拉出兩列...計數和總數,這將返回多行,但沒有上下文的帳戶或總計,但你可以調整,因爲你認爲合適。

SELECT PQ.count, 
     PQ.total 
    FROM (SELECT STRAIGHT_JOIN 
      t.account_number, 
      COUNT(t.id) count, 
      SUM(t.amount) total, 
      ib.id import_bundle_Id 
     FROM 
      transaction_code tc 
       join account_transaction t 
        on tc.id = t.transaction_import_id 
       join transaction_import ti 
        on t.transaction_import_id = ti.id 
       join generic_import gi 
        on ti.generic_import_id = gi.id 
       join import_bundle ib 
        on gi.import_bundle_id = ib.id 
       join account_import ai 
        on gi.id = ai.generic_import_id 
       join account a 
        on ai.id = a.account_import_id 
       join account_northway_product anp 
        on a.id = anp.account_id 
       join northway_product np 
        on anp.northway_product_id = np.id 
        AND np.code != '01' 
     where 
      tc.code in (0, 20, 40) 
     group by 
      t.account_number) PQ 
相關問題