2014-07-17 40 views
3

我必须优化其他人编写的查询,并且我正在努力工作。它有时需要超过12秒才能完成!如何优化带有多个连接和子查询的慢查询

我有一个SQL小提琴here,但是在那里那里有没有数据。我认为数据量部分是缓慢的原因(wed_supplies + postcodes中的20k,注释中的60k)以及num_reviewsavg_rating子查询。取出子查询将其取消为2秒钟,但我需要它们提供的值,并且它还需要更快。

SELECT *, c_title AS category, 

     (SELECT COUNT(*) FROM comments WHERE site_id = '96' AND ec_type = 'review' AND ec_link_id = ws_id) AS num_reviews, 
     (SELECT AVG(ec_rating) FROM comments WHERE site_id = '96' AND ec_type = 'review' AND ec_link_id = ws_id) AS avg_rating, 
     (((acos(sin((52.1528253 *pi()/180)) * sin((`p_lat`*pi()/180)) 
      +cos((52.1528253 *pi()/180)) * cos((`p_lat`*pi()/180)) 
      * cos(((-0.6800496 - `p_lng`)*pi()/180))))*180/pi())*60*1.1515) 
      AS distance 
     FROM wed_suppliers 
      LEFT JOIN postcodes ON p_postcode = REPLACE(ws_postcode, ' ', '') 
      LEFT JOIN c_content ON ws_category = c_id 
     WHERE wed_suppliers.site_id = '96' AND c_content.site_id = '96' 
     AND ws_hide = '0' 
     AND ws_permalink != '' 
     AND p_lat != '' AND p_lng != '' AND p_invalid = '0' 
     HAVING distance <= 10 

     ORDER BY distance ASC 
     LIMIT 0,20 

EXPLAIN

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 PRIMARY  wed_suppliers range ws_permalink,site_id,ws_category,ws_hide site_id  4 NULL 22628 Using where; Using temporary; Using filesort 
1 PRIMARY  postcodes eq_ref PRIMARY,p_invalid,p_lng,p_lat PRIMARY  12 func 1 Using where 
1 PRIMARY  c_content eq_ref PRIMARY,site_id  PRIMARY  4 engine_4.wed_suppliers.ws_category 1 Using where 
3 DEPENDENT SUBQUERY comments index_merge  site_id,ec_link_id,ec_type site_id,ec_type  4,34 NULL 1 Using intersect(site_id,ec_type); Using where 
2 DEPENDENT SUBQUERY comments index_merge  site_id,ec_link_id,ec_type site_id,ec_type  4,34 NULL 1 Using intersect(site_id,ec_type); Using where 

我已经使用的EXPLAIN返回什么this glossary,但没有多少运气。

如何优化此查询以便以更合理的速度运行?我如何将EXPLAIN翻译成更有用的东西。

+0

如果你可以修改数据库模式,你可以查看你的索引 – heringer

+0

@heringer索引是在sqlfiddle链接我发布在顶部 – Horse

+0

@Horse - 表不是很大。你可以尝试1:在运行查询之前清理数据,从而避免在连接中使用REPLACE函数? 2.为子查询创建临时表,然后将其与主查询结合起来? – Shiva

回答

1

看起来你的连接正在使用索引。这留下子查询:

(SELECT COUNT(*) FROM comments WHERE site_id = '96' AND ec_type = 'review' AND ec_link_id = ws_id) AS num_reviews, 
    (SELECT AVG(ec_rating) FROM comments WHERE site_id = '96' AND ec_type = 'review' AND ec_link_id = ws_id) AS avg_rating, 

我会推荐以下复合索引:comments(ec_link_id, ec_type, site_id)。这应该会加速子查询。

+0

我添加了以下内容,但是它使得执行时间差异很小 - ALTER TABLE'comments' ADD INDEX'comments_comp'(ec_link_id,ec_type,site_id) – Horse