简体   繁体   English

什么是优化此SQL查询的最佳方法

[英]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%. 我有以下SQL查询,但是我注意到它给我的服务器带来了压力,因为每次运行它时,CPU使用率都会以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 ... . 请提供SHOW CREATE TABLEEXPLAIN 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. 我不知道$cond应该是什么。 It is certainly not valid SQL syntax, so I'll ignore it. 它肯定不是有效的SQL语法,因此我将忽略它。

For this query, you wan the following indexes: companies(ifContractor, id) and newload(idCompany, smallstatus, loadrate, esmiles, id) . 对于此查询,您需要以下索引: companies(ifContractor, id)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? 也许20%并不那么糟糕? (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. 我试图将newLoads表上的聚合合并到单个SELECT中,并最终得到(非常)类似于Rick James已经拥有的东西。 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. 我的构造的另一个好处是,如果newLoads中没有匹配的信息和/或当字段之一为零时,它与原始查询更加一致。 (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 ; 无论如何,如果持续时间是一个问题,您可能要检查是否在相关字段(如Gordon Linoff)上正确建议了(复合)索引,以及$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..) PS:没有太多的mysql实际经验,我想知道l.esMiles <> '0'是否不比l.esMiles <> 0 “慢”,假设l.esMiles是一个数字字段(例如整数或十进制等。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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