2013-05-15 139 views
0

我有一個查詢:優化SQL查詢運行

SELECT `l`.`id`, `l`.`headline`, `l`.`description`, `l`.`image`, `l`.`campaign_id`, IF(l.required_impressions=0,0,1) AS sequence, (IFNULL(ROUND(COUNT(DISTINCT(lc.id))/COUNT(DISTINCT(li.id)), 3) * 100, 0) * 0.3) + (l.cost * 0.7) AS `scales`, `c`.`name` AS `campaign` 
FROM `app_links` AS `l` 
INNER JOIN `app_campaigns` AS `c` ON c.id = l.campaign_id 
LEFT JOIN `app_link_clicks` AS `lc` ON lc.link_id = l.id 
LEFT JOIN `app_link_impressions` AS `li` ON li.link_id = l.id 
LEFT JOIN `app_links_categories` AS `lcat` ON l.id = lcat.link_id 
LEFT JOIN `app_links_countries` AS `lcou` ON l.id = lcou.link_id 
WHERE lcat.category_id IN(3,7,14) 
AND lcou.country_id IN(89,147,124,131,259,197,88) 
GROUP BY `l`.`id` 
ORDER BY sequence DESC, `scales` DESC 
LIMIT 6 

的EXPLAIN查詢返回: enter image description here

你有什麼想法如何優化查詢?現在,它採取〜0.6秒,所以這是相當長的:/

+0

取下提供模式來自查詢的'lcat'和'lcou'項,因爲它們沒有被引用? (或者用一個普通的'JOIN'替換'LEFT JOIN',的確如此) – wildplasser

+0

是否有意使用'lcou.country_id'和'lcou'加入'LEFT JOIN'? 'lcat'的同一個問題。 – zerkms

+0

@wildplasser:它們被用在'WHERE'裏。 – zerkms

回答

2

只要你指的是lcatlcouWHERE子句中是沒有意義讓他們通過LEFT被連接加入。

所以我的建議是:對於lcat

  1. 變化LEFT JOINlcouINNER JOIN
  2. 移動這兩個連接上,因此所有INNER JOIN小號都在開始
  3. 移動lcatlcou條件對應的ON條款(這不應該改變任何東西,但會更具可讀性)
  4. 創建複合link_id + country_idlink_id + category_id指標
  5. 正如你所看到的 - MySQL優化順序改變了的表的連接,所以app_links在中間加入,似乎像app_links是MyISAM數據(它只是基於這樣的事實猜測,campaign_id沒有按看起來不像聚簇索引)。如果是這樣的 - 嘗試添加複合campaign_id + id指數爲它以及

PS:對上面的變化,提供了新的執行計劃

PPS:從查詢中的所有表

+0

不幸的是我使用Zend框架和構建上面查詢我查詢生成器,所以我不能重新排序所有連接(這是取決於PHP代碼)。 – BlueMan

+0

@BlueMan:如果您還有其他問題,至少應該做其他事情並提供執行計劃 – zerkms

+0

我更改link_categories順序,將左連接更改爲內連接。另外我添加了建議的索引。現在查詢在〜0.08秒內運行。解釋:http://tinypic.com/r/23wkx6t/5 每個表都是InnoDB。 – BlueMan