Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
慢MySQL查询,说明使用临时显示;使用文件排序_Mysql_Join_Explain - Fatal编程技术网

慢MySQL查询,说明使用临时显示;使用文件排序

慢MySQL查询,说明使用临时显示;使用文件排序,mysql,join,explain,Mysql,Join,Explain,此查询: EXPLAIN SELECT ppi_loan.customerID, loan_number, CONCAT(forename, ' ', surname) AS agent, name, broker, (SELECT timestamp FROM ppi_sar_status

此查询:

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
速度非常慢,下面是解释查询的所有结果

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
为什么要扫描这么多行,为什么要使用临时文件;使用文件排序?
我无法删除任何子查询,因为我需要它们生成的所有结果。正如在评论中所提到的,查询速度慢的主要原因是您似乎只有单列索引,而您需要多列索引来覆盖联接、筛选器和分组依据

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

尽管您仅对2个字段进行分组,但在选择列表中列出了其他几个字段,而不受聚合函数的约束,例如min。MySQL确实允许在某些sql模式设置下运行此类查询,但它们仍然违反sql标准,可能会产生意外的副作用,除非你真的知道自己在做什么

您在ppi_loan表上的联接条件(即左联接中的左表)中有筛选器。由于左连接的性质,这些记录不会从resultset中删除,但MySQL不会连接它们上的任何值。这些标准应移至where子句

我将创建的索引:

PixSalyStult:Load,状态,历史字段的多栏索引-我会考虑把它移到连接部分,因为这个表不存在

ppi_ques_status:loanID、status、timestamp字段上的多列索引-这将同时支持子查询和连接。记住,子查询在解释中也有filesort

ppi_loan:至少在customerID、loan_number字段上有一个多列索引,以支持group by子句,因此至少避免使用filesort。您可以考虑根据其对该索引的选择性,在联接标准中添加其他字段。


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

很明显,ppi_ques_status表中只有单字段索引,然而,您需要一个多字段索引来真正帮助您的查询。它扫描那么多行,因为有那么多行满足您为数据库提供的条件。使用where意味着它应用了一个索引来减少它必须查找的行数,而使用filesort则是因为它对记录进行了逐位排序,以便按照指定的顺序返回它们。filesort的命名很糟糕。它很慢,因为它从磁盘读取的速度很慢,而不是内存很快。@mjh您对解释的解释与实际含义有很大出入。能否添加from子句中那些字段来自哪个表,而您没有指明表名,例如loan_number?@mjh请参阅MySQL手册中的解释结果:。例如,您写道,它会扫描这么多行,因为有这么多行满足您为数据库提供的条件。实际上,它的意思是:rows列表示MySQL认为执行查询必须检查的行数。对于InnoDB表,这个数字是一个估计值,可能并不总是准确的。你可以检查所有其他的,你把它们都搞错了。查询很慢,因为它们是I/O/CPU绑定的,或者当有很多数据要返回时,这些数据必须经过缓冲,然后通过网络发送。您的答案只涉及索引。这对发送的数据量没有任何影响,只是更有效地减少了查找记录所浪费的I/O数量。对于今天的CPU来说,90k行甚至1m行都算不了什么,这清楚地表明使用了默认的innodb配置。即使可以提高索引的效率,但您只关注问题的一部分。此外,子查询===JOIN。我不会投票的。谢谢你,影子,这很有帮助。我来看看tomorrow@mjh正如OP所指出的,查询产生755条记录,因此通过网络进行缓冲和结束不是问题。子查询与联接不同。子查询与联接完全相同。它的解析和执行方式与编写连接时完全相同。在这种情况下,这是不相关的,因为提供的答案似乎足够了,其余的是测量电子喷丸。在我看来,如果答案中包含了额外的内容,那么这个答案就完整了。@N.B.对不起,只是因为你在这个论点中处于少数派,并不意味着你就自动正确了。关系代数是一回事,实际执行计划是另一回事。更不用说,有些子查询在没有子查询的情况下无法重新编写为联接。