[英]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.