MySQL查询速度慢,EXPLAIN显示使用临时;使用filesort

时间:2017-02-16 14:39:56

标签: mysql join explain

此查询:

EXPLAIN SELECT ppi_loan.customerID,
               loan_number,
               CONCAT(forename, ' ', surname) AS agent,
               name,
               broker,
              (SELECT timestamp
               FROM ppi_sar_status
               WHERE history = 0
                   AND (status = 10 || status = 13)
                   AND ppi_sar_status.loanID = ppi_loan.loanID) AS ppi_unsure_date,
              fosSent,
              letterSent,
              (SELECT timestamp
               FROM ppi_ques_status
               WHERE status = 1 
                   AND ppi_ques_status.loanID = ppi_loan.loanID
               ORDER BY timestamp DESC LIMIT 1) AS sent_date,
               ppi_ques_status.timestamp
FROM ppi_loan
LEFT JOIN ppi_assignments ON ppi_assignments.customerID = ppi_loan.customerID
LEFT JOIN italk.users ON italk.users.id = agentID
LEFT JOIN ppi_ques_status ON ppi_ques_status.loanID = ppi_loan.loanID
JOIN ppi_lenders ON ppi_lenders.id = ppi_loan.lender
JOIN ppi_status ON ppi_status.customerID = ppi_loan.customerID
JOIN ppi_statuses ON ppi_statuses.status = ppi_status.status
   AND ppi_ques_status.status = 1
   AND ppi_ques_status.history = 0
   AND (cc_type = '' || (cc_type != '' AND cc_accepted = 'no'))
   AND ppi_loan.deleted = 'no'
   AND ppi_loan.customerID != 10
GROUP BY ppi_loan.customerID, loan_number

非常慢,以下是EXPLAIN查询的所有结果

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY ppi_ques_status ref loanID,status,history   status  3   const   91086   Using where; Using temporary; Using filesort
1   PRIMARY ppi_loan    eq_ref  PRIMARY,customerID  PRIMARY 8   ppimm.ppi_ques_status.loanID    1   Using where
1   PRIMARY ppi_lenders eq_ref  PRIMARY PRIMARY 4   ppimm.ppi_loan.lender   1   Using where
1   PRIMARY ppi_assignments eq_ref  customerID  customerID  8   ppimm.ppi_loan.customerID   1   
1   PRIMARY users   eq_ref  PRIMARY PRIMARY 8   ppimm.ppi_assignments.agentID   1   
1   PRIMARY ppi_status  ref status,customerID   customerID  8   ppimm.ppi_loan.customerID   6   
1   PRIMARY ppi_statuses    eq_ref  PRIMARY PRIMARY 4   ppimm.ppi_status.status 1   Using where; Using index
3   DEPENDENT SUBQUERY  ppi_ques_status ref loanID,status   loanID  8   func    1   Using where; Using filesort
2   DEPENDENT SUBQUERY  ppi_sar_status  ref loanID,status,history   loanID  8   func    2   Using where

为什么要扫描这么多行以及为什么“使用临时;使用filesort”? 我无法删除任何子查询,因为我需要他们生成的所有结果

1 个答案:

答案 0 :(得分:0)

正如评论中已经提到的,查询速度慢的主要原因是您似乎只有单列索引,而您需要多列索引来覆盖连接,过滤器和组。 / p>

此外,您的查询还有其他两个问题:

  1. 即使您仅在2个字段上group by,其他几个字段也列在select列表中,而不受聚合函数的约束,例如min()。 MySQL允许在某些sql模式设置下运行此类查询,但它们仍然违反sql标准,可能会产生意想不到的副作用,除非你真的知道自己在做什么。

  2. 您在ppi_loan表格中的left join表格中有where左表格的过滤条件。由于左连接的性质,这些记录不会从结果集中消除,但MySQL不会在它们上加入任何值。这些标准应移至group by条款。

  3. 我要创建的索引:

    • ppi_sar_status:关于loanID,状态,历史记录字段的多列索引 - 我会考虑将其移至连接部分,因为此表不存在

    • ppi_ques_status:loanID,status,timestamp字段的多列索引 - 这将支持子查询和连接。请记住,子查询在解释中也有文件排序。

    • ppi_loan:至少是customerID上的多列索引,loan_number字段支持exists()子句,因此至少避免使用filesort。您可以考虑根据它们对此索引的选择性在连接条件中添加其他字段。

    我也不确定为什么你在连接中有最后2个状态表,因为你没有从中检索任何值。如果您使用这些表来消除某些记录,请考虑使用exists()子查询而不是连接。在连接中,MySQL需要从所有连接的表中获取数据,而在Foreground子查询中,它只检查结果集中是否存在至少1条记录而不从基础表中检索任何实际数据。