MySQL JOIN搜索太多行

时间:2017-08-30 12:10:34

标签: mysql join explain

我有一个带来8,566个结果的查询。但EXPLAIN显示一个表搜索233,190行,我不明白为什么。 它使用' status'显示问题表(ppi_sar_status)。密钥,但查询在不同的密钥' loanID'

上加入该表

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'

2 个答案:

答案 0 :(得分: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/

答案 1 :(得分: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'))

回答问题

我不知道你的显式索引,但为了覆盖索引并帮助进一步优化这个查询,我建议你各自的表上有以下索引。

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