简体   繁体   中英

Slow query with VIEW and LEFT OUTER JOIN

I'm trying to get a 30 day view of transaction totals as a graph. Currently using a VIEW for dates and LEFT OUTER JOIN to get data. This works, showing my SUM of all my transactions, and still including a 0 for days without transactions, etc.

The problem is that the transactions table is quite large. So that LEFT OUTER JOIN is doing a lot of work... and is slow. Here is the original query:

SELECT IFNULL(SUM(Total), 0) AS OrderTotal, MONTH(dates.date) AS Month, YEAR(dates.date) AS Year, DAY(dates.date) AS Day
FROM dates LEFT OUTER JOIN tblTransactions
ON DATE(tblTransactions.TransDate) = dates.date
WHERE dates.date > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DAY(dates.date), MONTH(dates.date)
ORDER BY dates.date
LIMIT 30

To speed things up, I thought it would be good to add an additional WHERE condition and only look at transactions older than 30 days. That sped things up incredibly, and thought I dialed it, but the problem is that it's only good if I have transactions for all 30 days. If one day is $0, it would return 29 records with this conditional. Not good.

SELECT IFNULL(SUM(Total), 0) AS OrderTotal, MONTH(dates.date) AS Month, YEAR(dates.date) AS Year, DAY(dates.date) AS Day
FROM dates LEFT OUTER JOIN tblTransactions
ON DATE(tblTransactions.TransDate) = dates.date
WHERE dates.date > DATE_SUB(NOW(), INTERVAL 30 DAY)
AND tblTransactions.TransDate > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DAY(dates.date), MONTH(dates.date)
ORDER BY dates.date
LIMIT 30

So was hoping for some feedback to improve the original query. Right now, I have a feeling a PHP for() loop - looping 30 times and querying 30 times might be faster than my original LEFT OUTER JOIN single query.

The filtering on the second table in a left join needs to go in the on clause:

SELECT COALESCE(SUM(t.Total), 0) AS OrderTotal,
       MONTH(d.date) AS Month, YEAR(dates.date) AS Year, DAY(d.date) AS Day
FROM dates d LEFT OUTER JOIN
     tblTransactions t
     ON DATE(t.TransDate) = d.date AND
        t.TransDate > DATE_SUB(NOW(), INTERVAL 30 DAY)
WHERE d.date > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DAY(d.date), MONTH(d.date)
ORDER BY d.date
LIMIT 30;

Note: A cause for bad performance is likely this clause:

DATE(t.TransDate) = d.date

If TransDate has no time component then this is not necessary. If performance on this type of query is important, add a computed column for just the date component of TransDate and add an index on that column.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM