2014-09-22 95 views
0

我有查询到最多40秒来执行,我想知道如何使它更快...优化SQL查询

SELECT rp.`id` as rip,r.`id`, 
    rl.`id` as rlid, r.`number`, r.`type`, 
    a.`title` as atitle, a.`id` as aid, more, 
    more_valid 
FROM 
    `R_l_p` rp INNER JOIN 
    `Rl` rl ON rp.`rl_id` = rl.`id` INNER JOIN 
    `R` r ON r.`id` = rl.`r_id` INNER JOIN 
    `A` a ON a.`id` = r.`a_id` 
    LEFT JOIN 
    (SELECT `type`, `v`, `r_id`, COUNT(*) AS more 
    FROM `R_l` 
    WHERE `type` = 'stream' AND `v` = 1 
    GROUP BY `r_id`) stm ON stm.`r_id` = r.`id` 
    LEFT JOIN 
    (SELECT `type`, `v`, `r_id`, COUNT(*) AS more_valid 
    FROM `R_l` 
    WHERE `type` = 'stream' AND `v` = 0 
    GROUP BY `r_id`) morelink ON morelink.`r_id` = r.`id` 
WHERE rp.`link` = 'dead' AND rl.`type` = 'stream' 
ORDER BY rip ASC 
LIMIT 0, 1000 
 
+-----+--------------+---------------+---------+--------------------------+-------------+----------+---------------------------+--------+----------------------------------------------+ 
| id | select_type | table  | type |  possible_keys  | key  | key_len |   ref    | rows |     Extra      | 
+-----+--------------+---------------+---------+--------------------------+-------------+----------+---------------------------+--------+----------------------------------------------+ 
| 1 | PRIMARY  | r    | ALL  | PRIMARY,a_id    | NULL  | NULL  | NULL      | 21804 | Using temporary; Using filesort    | 
| 1 | PRIMARY  | a    | eq_ref | PRIMARY     | PRIMARY  | 4  | db453988339.r.a_id  |  1 |            | 
| 1 | PRIMARY  | rl   | ref  | PRIMARY,r_id,type  | r_id  | 4  | db453988339.r.id   |  1 | Using where         | 
| 1 | PRIMARY  | derived2  | ALL  | NULL      | NULL  | NULL  | NULL      | 21077 |            | 
| 1 | PRIMARY  | derived3  | ALL  | NULL      | NULL  | NULL  | NULL      |  1 |            | 
| 1 | PRIMARY  | rp   | eq_ref | rl_id     | rl_id  | 4  | db453988339.rl.id   |  1 | Using where         | 
| 3 | DERIVED  | R_link  | ALL  | type      | NULL  | NULL  | NULL      | 27580 | Using where; Using temporary; Using filesort | 
| 2 | DERIVED  | R_link  | ALL  | type      | NULL  | NULL  | NULL      | 27580 | Using where; Using temporary; Using filesort | 
+-----+--------------+---------------+---------+--------------------------+-------------+----------+---------------------------+--------+----------------------------------------------+ 

谢谢:)

+0

当你删除这些2左联接请问你的查询执行? – Leo 2014-09-22 21:58:12

+1

左连接点是什么?你不是指任何地方 – FuzzyTree 2014-09-22 22:05:42

+1

他使用从左连接越来越more_valid作为选择子句 – Leo 2014-09-22 22:09:29

回答

5

一件事,我会用一个内嵌视图替换两个内联视图,通过将条件从WHERE子句移动到SELECT列表中的表达式中,从同一个内联视图中返回moremore_valid),并删除more_link视图。

我修改stm联视图是这样的:

 (SELECT q.r_id 
       , SUM(q.v=1) AS `more` 
       , SUM(q.v=0) AS `more_valid` 
      FROM `R_l` q 
      WHERE q.type = 'stream' 
      GROUP BY q.r_id 
     ) stm 

我还提供覆盖索引,以优化联视图查询,例如:

CREATE INDEX R_1_IX1 ON R_1 (type, r_id, v) 

通过引用列type上的等式谓词,MySQL可能能够使用索引优化GROUP BY操作(避免使用“使用filesort”操作)。我们希望在解释的额外列中看到“使用索引”。

不幸的是,派生表不会被编入索引。但至少在这种变化的情况下,你只能实现一个内联视图,避免额外的联接操作。


也就是说,我会更换这些两行:

LEFT JOIN (SELECT `type`, `v`, `r_id`, COUNT(*) AS more FROM `R_l` WHERE `type` = 'stream' AND `v` = 1 GROUP BY `r_id`) stm ON stm.`r_id` = r.`id` 
LEFT JOIN (SELECT `type`, `v`, `r_id`, COUNT(*) AS more_valid FROM `R_l` WHERE `type` = 'stream' AND `v` = 0 GROUP BY `r_id`) morelink ON morelink.`r_id` = r.`id` 

有了这个:

LEFT 
    JOIN (SELECT q.r_id 
       , SUM(q.v=1) AS `more` 
       , SUM(q.v=0) AS `more_valid` 
      FROM `R_l` q 
      WHERE q.type = 'stream' 
      GROUP BY q.r_id 
     ) stm 
    ON stm.r_id = r.id 
+0

我应该添加索引,即使我已经有一个类型,r_id和v ? – cloud1250000 2014-09-22 22:16:58

+0

从40secs到2secs更好。谢谢 – cloud1250000 2014-09-22 22:21:47

+0

@ cloud1250000:“使用filesort”操作可能很昂贵,特别是在大型设备上。有时可能让MySQL避免该操作,并使用索引。 (当需要“分组”在一起的行在索引中是连续的时,MySQL可以在不实现行的情况下得到结果;当查询可以仅从索引得到满足时,不查找底层的数据页表,这就是所谓的“覆盖”索引,我们将在EXPLAIN输出中看到“使用索引”,但是对派生表的连接仍然会很昂贵。 – spencer7593 2014-09-22 22:21:51