优化sql查询运行时

时间:2013-05-15 12:02:48

标签: mysql sql optimization

我有一个问题:

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秒,所以它很长:/

1 个答案:

答案 0 :(得分:2)

只要您在lcat子句中引用lcouWHERE,就无法通过LEFT加入来加入它们。

所以我的建议是:

  1. LEFT JOINlcat改为lcouINNER 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索引
  6. PS:进行上述更改并提供新的执行计划

    PPS:为查询中的所有表提供架构