The following query runs quickly except when I add in the 'areacode.hours = 2'. Instead of taking a second it now takes close to a minute.
SELECT lead.id, first, last, lead.phone, valid_phone, mobile_phone
FROM lead
LEFT JOIN dnt ON dnt.phone = lead.phone
LEFT JOIN areacode ON areacode.code = LEFT(lead.phone, 3)
LEFT JOIN campaign ON campaign.id = lead.campaign_id
WHERE dnt.id IS NULL
AND campaign.lft BETWEEN 0 AND 1000
AND lead.datetime BETWEEN '2017-06-01 00:00:00' AND '2017-06-01 23:59:59'
AND areacode.hours = 2
GROUP BY lead.phone
ORDER BY lead.phone DESC
LIMIT 1,1000
Results of EXPLAIN
1 SIMPLE lead index campaign_id,datetime phone 13 NULL 181181 Using where
1 SIMPLE campaign eq_ref PRIMARY PRIMARY 4 data3_db.lead.campaign_id 1 Using where
1 SIMPLE areacode ref code,hours code 11 func 1 Using index condition; Using where
1 SIMPLE dnt ref phone phone 12 data3_db.lead.phone 1 Using where; Using index; Not exists
Your where clause limits are being executed after the joins complete. This will result in your left joins acting like INNER joins. I would recommend moving the limits for those tables on the right side of a left join to the joins themselves; so the limits are applied before the join occurs. (or as part of it)
Exception would be if you're checking for Null on a field; That could remain in the where clause. but you have no way to distinguish between dnt.ids which are are null in the table, and those which are null as part of the left join if you put it in the where clause. However, given this is an "ID" field I'll assume it can't be null and leaving it in the where makes sense.
At times the compiler may attempt to apply the filter after the join when you have thousands of records * 4 tables you record growth could be large; by moving the limits to occur before/on join, the engine can reduce the temporary datset it has to build before it filters out the records. On Inner joins this doesn't matter but on outer joins it can not only effect performance; but desired results.
SELECT lead.id, first, last, lead.phone, valid_phone, mobile_phone
FROM lead
LEFT JOIN dnt
ON dnt.phone = lead.phone
LEFT JOIN areacode
ON areacode.code = LEFT(lead.phone, 3)
AND areacode.hours = 2
LEFT JOIN campaign
ON campaign.id = lead.campaign_id
AND campaign.lft BETWEEN 0 AND 1000
WHERE lead.datetime BETWEEN '2017-06-01 00:00:00' AND '2017-06-01 23:59:59'
AND dnt.id IS NULL
GROUP BY lead.phone
ORDER BY lead.phone DESC
LIMIT 1,1000
If that still doesn't produce the desired results and time, then i'd look at desired indexes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.