[英]What is the best way to optimize this sql query
我有以下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
这可能会更有效:
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;
请提供SHOW CREATE TABLE
和EXPLAIN SELECT ...
这是您的查询:
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)
。
顺便说一句,如果其值看起来像数字的列实际上是数字,则请删除单引号。 类型转换会混淆优化器。
也许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是一个数字字段(例如整数或十进制等。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.