I have the following SQL query, but i noticed that it's putting some pressure on my server since every time i run it, the CPU usage jumps with good 20%.
SELECT
c.name, c.billingaddress, c.billingcity, c.billingstate, c.billingzip,c.ifActive,
(SELECT COUNT(l.id) FROM newLoads l WHERE l.idCompany = c.id AND l.smallStatus='1') as numberLoads,
(SELECT (SUM(l.loadRate))/(SUM(l.esMiles)) FROM newLoads l WHERE l.idCompany = c.id AND l.loadRate != '0' AND l.esMiles != '0' AND l.smallStatus='1') as RPM
FROM `companies` c WHERE ifContractor ='0' $cond
ORDER BY numberLoads DESC
This might be more efficient:
SELECT c.name, c.billingaddress, c.billingcity,
c.billingstate, c.billingzip, c.ifActive,
x.numberLoads, x.RPM
FROM
( SELECT l.idCompany,
COUNT(*) AS numberLoads,
SUM(l.loadRate))/(SUM(l.esMiles) AS RPM
FROM newLoads l
WHERE l.smallStatus = '1'
) AS x
JOIN companies AS c ON c.id = x.idCompany
WHERE ifContractor = '0' $cond
ORDER BY x.numberLoads DESC;
Please provide SHOW CREATE TABLE
and EXPLAIN SELECT ...
.
This is your query:
SELECT c.name, c.billingaddress, c.billingcity, c.billingstate, c.billingzip, c.ifActive,
(SELECT COUNT(l.id)
FROM newLoads l
WHERE l.idCompany = c.id AND l.smallStatus = '1'
) as numberLoads,
(SELECT (SUM(l.loadRate))/(SUM(l.esMiles))
FROM newLoads l
WHERE l.idCompany = c.id AND l.loadRate <> '0' AND l.esMiles <> '0' AND l.smallStatus = '1'
) as RPM
FROM `companies` c
WHERE ifContractor = '0' $cond
ORDER BY numberLoads DESC;
I don't know what $cond
is supposed to be. It is certainly not valid SQL syntax, so I'll ignore it.
For this query, you wan the following indexes: companies(ifContractor, id)
and newload(idCompany, smallstatus, loadrate, esmiles, id)
.
By the way, if the columns whose values look like numbers really are numbers, then drop the single quotes. Type conversion can confuse the optimizer.
Maybe 20% isn't all that bad? (especially if it's only for a short burst) By the looks of it, it might need to run over quite a bit of data to get its result.
I tried to merge the aggregations on the newLoads
table into a single SELECT and ended up with something (very) similar what Rick James already had. The added benefit of my construction is that it keeps more in line with the original query in case there is no matching information in newLoads and/or when one of the fields there is zero. (I think, didn't really test it out)
SELECT c.name, c.billingaddress, c.billingcity, c.billingstate, c.billingzip, c.ifActive, agg.numberLoads, agg.RPM
FROM `companies` c
LEFT OUTER JOIN ( (SELECT l.idCompany,
numberLoads = COUNT(l.id),
RPM = (CASE WHEN SUM((CASE WHEN l.loadRate <> '0' AND l.esMiles <> '0' THEN 1 ELSE 0 END)) = 0 THEN NULL ELSE
SUM((CASE WHEN l.loadRate <> '0' AND l.esMiles <> '0' THEN l.loadRate ELSE 0 END)) / SUM((CASE WHEN l.loadRate <> '0' AND l.esMiles <> '0' THEN l.esMiles ELSE 0 END))
END)
FROM newLoads l
WHERE l.smallStatus = '1'
) AS agg
ON agg.idCompany = c.id
WHERE c.ifContractor = '0' $cond
ORDER BY agg.numberLoads DESC;
Anyway, if duration is an issue, you might want to check if you have (compound) indexes on the relevant fields like Gordon Linoff rightfully suggested, and also on what might be in $cond
; it probably would make sense to see what kind of filtering is going on there and what effect it has on the overall performance of the query.
PS: not having much hands-on experience with mysql I was wondering if l.esMiles <> '0'
isn't "slower" than l.esMiles <> 0
, under the assumption that l.esMiles is a numeric field (eg integer or decimal etc..)
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.