MySQL 查詢優化 - 關聯查詢


1. 關聯查詢執行流程

MySQL執行關聯查詢的策略很簡單,他會從一個表中循環取出單條數據,然后用該條數據到下一個表中尋找匹配的行,然后回溯到上一個表,到所有的數據匹配完成為止。因此也被稱為“嵌套循環關聯”。

來看下面這個SQL:

select tb1.col1, tb2,col2
  from tb1 inner join tb2 using(col3)
  where tb1.col1 in (5,6)

他的執行順序為(偽代碼):

List outerDataList = "select * from tb1 where col1 in (5,6)"
  for(outerData in outerDataList){
    List innerDataList = "select * from tb2 where col3 = outerData.col3"
      for(innerData : innerDataList){
        output(outterData,innerData)
      }
  }

MySQL認為所有的查詢都是一次關聯查詢,所以如果查詢一個表,上述過程也適合,不過只需要完成上面外層的基本操作。

再來看看left outter join查詢的過程,SQL如下:

select tb1.col1, tb2,col2
from tb1 left outer join tb2 using(col3)
where tb1.col1 in (5,6)

偽代碼如下:

List outerDataList = "select * from tb1 where col1 in (5,6)"
  for(outerData in outerDataList){
    List innerDataList = "select * from tb2 where col3 = outerData.col3"
      if(innerDataList != null){
        for(innerData : innerDataList){
          output(outterData,innerData)
        }
      }else{
        // inner表無對應數據,以outter數據為准
        output(outterData,null)
      }
  }

但是這種遍歷的查詢方式不能滿足所有的聯合查詢,比如“全外連接”查詢(full outer join)不能使用該方法來實現,這可能是MySQL不支持全外接查詢的原因 ~~~

2. 優化

MySQL會將查詢命令生成一顆指令樹,比如四表聯合查詢的指令樹如下:

MySQL在生成指令樹之前會先對SQL語句的執行效率進行評估,然后選擇他認為效率最高的關聯順序執行。對於如下SQL:

EXPLAIN SELECT
	actor.NAME,
	film.title 
FROM
	actor actor
	INNER JOIN film_actor USING ( actor_id )
	INNER JOIN film USING ( film_id )

從執行計划可以看出,MySQL選擇將film作為第一個關聯表,拿到數據后再依次掃描film_actor、actor表取數據。MySQL的選擇策略是,盡量讓查詢執行更少的嵌套循環和回溯操作,因此,他會盡量將外層查詢的數據量更少。因為film表只有4條記錄,actor表有6條記錄,因此他認為選擇將film作為第一個表開始查詢有更高的執行效率。

但是MySQL的優化策略會比這復雜的多,MySQL會計算所有執行順序的代價,然后選擇他認為的最佳執行計划。但是,如果聯合查詢的表比較多,他不一定能窮舉所有的執行情況選擇最佳的執行策略,所以這種默認的優化方式卻不一定總是最佳的。還是以上條SQL為例子,假設在film表的film_id字段上建立了索引,那么即使film上的字段少於actor,可能使用actor表作為第一個表進行查詢,效率會更高(里層嵌套查詢film表數據時可以使用索引)。如果你認為有更佳的執行順序,可以使用STRAIGHT_JOIN關鍵字強行執行查詢順序:

EXPLAIN SELECT
	actor.NAME,
	film.title 
FROM
	actor actor
	STRAIGHT_JOIN film_actor USING ( actor_id )
	STRAIGHT_JOIN film USING ( film_id )

注意:絕大多數時候,MySQL做出的判斷都比人類要准確,絕大多數時候,不推薦強制執行順序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM