1. 程式人生 > >[慢查優化]聯表查詢注意誰是驅動表 & 你搞不清楚誰join誰更好時請放手讓mysql自行判定

[慢查優化]聯表查詢注意誰是驅動表 & 你搞不清楚誰join誰更好時請放手讓mysql自行判定

夠複雜吧。Nested Loop Join 就是這樣, 以驅動表的結果集作為迴圈的基礎資料,然後將結果集中的資料作為過濾條件一條條地到下一個表中查詢資料,最後合併結果;此時還有第三個表,則將前兩個表的 Join 結果集作為迴圈基礎資料,再一次通過迴圈查詢條件到第三個表中查詢資料,如此反覆。 這條語句的執行計劃如下:     id  select_type  table   type    possible_keys   key             key_len  ref                     rows  Extra                                       
------  -----------  ------  ------  --------------  --------------  -------  -------------------  -------  --------------------------------------------
     1  SIMPLE       mb      index   userid          userid          4        (NULL)               6060455  Using index; Using temporary; Using filesort
     1  SIMPLE       mbei    eq_ref  mb_id  mb_id  4        mb.id             1                                              
     1  SIMPLE       u       eq_ref  PRIMARY         PRIMARY         4        mb.uid        1  Using index                                 由於動用了“LEFT JOIN”,所以攻城獅已經指定了驅動表,雖然這張驅動表的結果集記錄數達到百萬級! . . 如何優化? . . 優化第一步:LEFT JOIN改為JOIN
幹嘛要 left join 啊?直接 join!
explain SELECT mb.id……
FROM mb JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid   WHERE 1=1   ORDER BY mbei.apply_time DESC limit 0,10
立竿見影,驅動表立刻變為小表 mbei 了, Using temporary 消失了,影響行數少多了:     id  select_type  table   type    possible_keys   key      key_len  ref                             rows  Extra         
------  -----------  ------  ------  --------------  -------  -------  ----------------------------  ------  --------------
     1  SIMPLE       mbei   
ALL     mb_id  (NULL)   (NULL)   (NULL)                         13383  Using filesort
     1  SIMPLE       mb      eq_ref  PRIMARY,userid  PRIMARY  4        mbei.mb_id       1                
     1  SIMPLE       u       eq_ref  PRIMARY         PRIMARY  4        mb.uid                1  Using index  
優化第一步之分支1:根據驅動表的欄位排序,好嗎?
left join不變。幹嘛要根據非驅動表的欄位排序呢?我們前面說過“對驅動表可以直接排序,對非驅動表(的欄位排序)需要對迴圈查詢的合併結果(臨時表)進行排序!”的。
explain SELECT mb.id……
FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid   WHERE 1=1   ORDER BY mb.id DESC limit 0,10
也滿足業務場景,做到了rows最小:     id  select_type  table   type    possible_keys   key             key_len  ref                    rows  Extra      
------  -----------  ------  ------  --------------  --------------  -------  -------------------  ------  -----------
     1  SIMPLE       mb      index   userid          PRIMARY         4        (NULL)                   10             
     1  SIMPLE       mbei    eq_ref  mb_id  mb_id  4        mb.id            1  Using index
     1  SIMPLE       u       eq_ref  PRIMARY         PRIMARY         4        mb.uid       1  Using index
優化第二步:去除所有JOIN,讓MySQL自行決定!
寫這麼多密密麻麻的 left join/inner join 很開心嗎?
explain SELECT mb.id……
FROM mb,mbei,u   
WHERE
    mb.id=mbei.mb_id
    and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10
立竿見影,驅動表一樣是小表 mbei: