我有一个带来8,566个结果的查询。但EXPLAIN显示一个表搜索233,190行,我不明白为什么。 它使用' status'显示问题表(ppi_sar_status)。密钥,但查询在不同的密钥' loanID'
上加入该表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)
这是由于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