慢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.对不起,只是因为你在这个论点中处于少数派,并不意味着你就自动正确了。关系代数是一回事,实际执行计划是另一回事。更不用说,有些子查询在没有子查询的情况下无法重新编写为联接。