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

时间:2016-01-16 17:57:23

标签: mysql sql query-optimization

我有以下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

3 个答案:

答案 0 :(得分:2)

可能效率更高:

SHOW CREATE TABLE

请提供EXPLAIN SELECT ...Ant_Table

答案 1 :(得分:1)

这是您的查询:

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;

我不知道$cond应该是什么。它肯定不是有效的SQL语法,所以我会忽略它。

对于此查询,您需要使用以下索引:companies(ifContractor, id)newload(idCompany, smallstatus, loadrate, esmiles, id)

顺便说一句,如果值看起来像数字的列确实是数字,那么删除单引号。类型转换可能会使优化程序混淆。

答案 2 :(得分:1)

也许20%并不是那么糟糕? (特别是如果它仅用于短暂的突发)从它的外观来看,它可能需要运行相当多的数据才能得到它的结果。

我尝试将newLoads表上的聚合合并到一个SELECT中,最后得到的东西(非常)类似于Rick James已有的东西。我的构造的额外好处是,如果newLoads中没有匹配信息和/或其中一个字段为零,它与原始查询保持更多一致。 (我想,并没有真正考验出来)

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;

无论如何,如果持续时间是一个问题,你可能想检查你是否有相关领域的(复合)索引,如Gordon Linoff正确建议的,以及$cond中可能存在的内容;看看那里发生了什么样的过滤以及它对查询整体性能的影响可能是有意义的。

PS:没有太多关于mysql的实践经验我想知道l.esMiles <> '0'是不是比l.esMiles <> 0“慢”,假设l.esMiles是一个数字字段(例如整数)或十进制等。)