2017-08-30 77 views
1

我有一個查詢,帶出了8,566個結果。但是EXPLAIN顯示了一個表格搜索233,190行,我看不出爲什麼。 它顯示了使用「狀態」鍵的問題表(ppi_sar_status),但查詢連接到該表上「的LoanID」MySQL JOIN搜索太多行

View the EXPLAIN results

SELECT DISTINCT 
     ppi_loan.loanID, 
     ppi_loan.lender, 
     ppi_loan.customerID, 
     ppi_loan.agreementNo, 
     loan_number, 
     ppi_lenders.name, 
     ppi_status.status, 
     ppi_statuses.description, 
     ppi_loan.broker, 
     (SELECT sarSent 
      FROM ppi_sar 
      WHERE ppi_sar.customerID = ppi_loan.customerID 
       AND ppi_sar.lender = ppi_loan.lender 
      ORDER BY sarSent DESC 
      LIMIT 1) as sarSent, 
     (SELECT COUNT(DISTINCT(groupID)) 
      FROM ppi_mdrs 
      WHERE ppi_mdrs.customerIDfk = ppi_loan.customerID 
       AND ppi_mdrs.lender = ppi_loan.lender 
       AND sent_to_lender = '0000-00-00 00:00:00') AS mdrs_sent, 
     (SELECT sent 
      FROM ppi_mdrs 
      WHERE ppi_mdrs.customerIDfk = ppi_loan.customerID 
       AND ppi_mdrs.lender = ppi_loan.lender 
      ORDER BY sent DESC 
      LIMIT 1) AS mdr_last_sent, 
     mobilePhone, 
     homePhone, 
     title, 
     firstName, 
     lastName, 
     loaSent 
    FROM 
     ppi_loan 
     JOIN ppi_sar_status 
      ON ppi_loan.loanID = ppi_sar_status.loanID 
     JOIN ppi_customer 
      ON ppi_loan.customerID = ppi_customer.customerID 
     JOIN ppi_lenders 
      ON ppi_loan.lender = ppi_lenders.id 
     JOIN ppi_status 
      ON ppi_loan.customerID = ppi_status.customerID 
      JOIN ppi_statuses 
       ON ppi_status.status = ppi_statuses.status 
     LEFT JOIN ppi_mdrs 
      ON ppi_loan.customerID = customerIDfk 
      AND ppi_loan.lender = ppi_mdrs.lender 
    WHERE 
      ppi_loan.customerID != 10 
     AND ppi_status.status != 9 
     AND ppi_status.status != 32 
     AND ppi_status.status != 54 
     AND ppi_status.status != 58 
     AND ppi_status.status != 59 
     AND ppi_status.status != 61 
     AND ppi_status.status != 69 
     AND ppi_status.status != 60 
     AND ppi_status.history = 0 
     AND ppi_loan.customerID 
     IN (SELECT customerID 
       FROM ppi_status 
       WHERE (status = 5 || status = 6 || status = 79) 
        AND timestamp > '2015-04-01' 
        AND ppi_status.customerID = ppi_loan.customerID) 
     AND ppi_sar_status.status = 16 
     AND ppi_sar_status.history = 0 
     AND (cc_type = '' || (cc_type != '' AND cc_accepted = 'no')) 
     AND ppi_loan.deleted = 'no' 
+0

您的桌子上是否有任何索引設置? –

+1

是的,EXPLAIN結果顯示可能的鍵 – swdee

回答

1

這是由於WHERE子句一個不同的充鍵:

ppi_sar_status.status = 16 

我可能會說很多這樣說,但也許你應該嘗試使用索引提示。 https://dev.mysql.com/doc/refman/5.7/en/index-hints.html

(但是不要忘了閱讀的告誡http://www.mysqldiary.com/the-battle-between-force-index-and-the-query-optimizer/

+0

是的,其中ppi_sar_status.status = 16,但僅用於結果中的貸款,這就是爲什麼它加入到ppi_sar_status.loanID = ppi_loan.loanID – swdee

+0

@swdee我猜查詢優化程序決定首先要做到這一點,因爲它認爲它會變得更快。您是否遇到此查詢的特定性能問題?查詢優化器完全可以自由裁剪一個表格,以表達您所需要的結果* *之前*與該表格進行連接,而不是之後;它不能保證它執行任務的順序。 –

+0

如果刪除'ppi_sar_status.status = 16',你會得到多少結果? – ivo

0

清潔您的查詢的可讀性和張貼的編輯後,我看到了「||」通常與語言中的邏輯OR相關聯的組件。但是,在MySQL中,似乎表示串聯值等字符串。

在您的WHERE子句中後期...

WHERE (status = 5 || status = 6 || status = 79) 
        AND timestamp > '2015-04-01' 
        AND ppi_status.customerID = ppi_loan.customerID) 
     AND ppi_sar_status.status = 16 
     AND ppi_sar_status.history = 0 
     AND (cc_type = '' || (cc_type != '' AND cc_accepted = 'no')) 

它看起來像你應該有邏輯 「或」 如

WHERE (status = 5 OR status = 6 OR status = 79) 

也..

 AND (cc_type = '' OR (cc_type != '' AND cc_accepted = 'no')) 

REVISION TO ANSWER

我不知道你的顯式索引,但要覆蓋索引並幫助進一步優化這個查詢,我會建議您在各自的表上使用以下索引。

table   index 
ppi_sar   (customerID, lender) *or lender,customerid either way* 
ppi_mdrs  (customerIdfk, lender, sent_to_lender) *or lender,customerid,sent...* 
ppi_sar_status (loanid, status, history) 
ppi_status  (customerID, status, history, timestamp) *timestamp optional* 

但是,現在所有這一切,我還會做更多的事情。 MySQL有一個特殊的關鍵字「STRAIGHT_JOIN」,告訴MySQL按照我告訴你的順序查詢,不要爲我想。正如它聲音一樣,它試圖將你的狀態表作爲主要狀態表。但是既然你真正的駕駛臺是貸款的,並且首先在你的FROM子句中,那麼這應該是查詢的基礎。所以我會更改爲

SELECT STRAIGHT_JOIN DISTINCT ... rest of query 
+0

結果是一樣的 – swdee

+0

[您可以使用||對於MySQL中的邏輯OR](https://dev.mysql.com/doc/refman/5.7/en/logical-operators.html)。我不認爲*您可以在MySQL中使用它進行字符串連接,但它是Oracle SQL中的字符串連接運算符。不過,您應該更喜歡使用「OR」作爲邏輯OR,因爲它更標準。 –

+0

@swdee,查看索引和新特殊關鍵字的修訂答案。 – DRapp