2014-09-22 30 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