简体   繁体   中英

What is the best way to optimize this sql query

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.

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