數據庫優化SQL優化之SELECT優化 ——JOIN和LEFT JOIN 和 RIGHT JOIN

         在數據庫的應用中,我們經常需要對多表進行連表操作來獲得關係型的數據,因此,應該更加的掌握好

SQL語句的join原理,因爲,可以稍一不慎,可能一個不好的join導致數據庫的全表掃描,查詢出大量的

無用的信息,並且對數據庫性能影響極大。

         數據庫中的join操作,實際上是對一個表和另一個表的關聯,而很多錯誤的理解爲,先把這兩個表來一個

迪卡爾積,然後扔到內存,用where和having條件來慢慢篩選,其實數據庫沒那麼笨的,那樣會佔用大量的內

存,而且效率不高,比如,我們只需要的一個表的一些行和另一個表的一些行,如果全表都做迪卡爾積,這開

銷也太大了,真正的做發是,根據在每一個表上的條件,邊遍歷一個表的同時,遍歷其他表,找到滿足最後的

條件後,就發送到客戶端,直到最後的數據全部查完,叫做嵌套循環查詢。

1,LEFT JOIN 和 RIGHT JOIN優化

在MySQL中,實現如 A LEFT JOIN B join_condition 如下:

          1,表B依賴賴與表A及所有A依賴的表

          2,表A依賴於所有的表,除了LEFT JOIN 的表(B)

          3,join_condition決定了怎樣來讀取表B,where條件對B是沒有用的

          4,標準的where會和LEFT JOIN聯合優化

          5,如果在A中的一行滿足where和having條件,B中沒有,會被填充null

 RIGHT JOIN 與LEFT JOIN類似,這個位置是可以互換的

2.1、LEFT JOIN 與 正常JOIN之間的轉換

        原則:當where條件,對於生成的null行總返回false時,可以直接轉化爲

                     正常的join

        如:

SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;
        將被轉換爲:

SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;
        注:因爲設置了條件t2.column2 =  5,那麼對於所有的生成的t2爲null的行都是不成立的

                這樣的優化將非常快速,因爲這樣相當於把外連接轉換爲等值連接,少了很多行

                的掃描和判斷。

2.2嵌套循環JOIN算法----Nested-Loop Join 

        簡單的嵌套循環算法就是從一個表開始,通過對錶的條件找到一行,然後找下一個表

        的數據,找完後,又回到第一個表來尋找滿足條件的行


例如,有三個表t1, t2, t3,他們的join類型爲:

Table   Join Type
t1      range
t2      ref
t3      ALL
即,t1表通過範圍掃描,t2關聯t1,t3爲全表掃描

這三個表的僞代碼爲:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions,
         send to client
    }
  }
}
注:意思是:先根據對t1表的條件範圍找到一行,和t2匹配,然後尋找t3的滿足條件的行

         如此循環迭代,最終找到全部滿足條件的行。

2.3塊嵌套循環JOIN算法 ---- Block Nested-Loop Join

         這個算法的應用爲:由於之前的嵌套算法每讀一個表的一行後,就會讀下表,這樣

          內部的表會被讀很多次,所以,數據庫利用了join緩存(join buffer)來存儲中間的結

          果,然後讀取內部表的時候,找到一行,都和這個緩存中的數據比較,以此來提高

          效率。例如:一次從外表讀10行,然後讀內部表時,都和這10行數據進行比較。

MySQL使用join buffer的條件爲:

          1,join_buffer_size系統變量決定了每個join使用的buffer大小

          2,join類型爲index或all時,join buffer才能被使用

          3,每一個join都會分配一個join buffer,即一個sql可能使用多個join buffer

          4,join buffer 不會分配給第一個非常量表

          5,只有需要引用的列會被放到join buffer中,不是整行

如以下例子:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    store used columns from t1, t2 in join buffer
	    這裏將t1和t2使用的列存到join buffer中
	    if buffer is full {
      for each row in t3 {
        for each t1, t2 combination in join buffer {
          if row satisfies join conditions,
          send to client
        }
      }
      empty buffer
    }
  }
}

if buffer is not empty {
  for each row in t3 {
    for each t1, t2 combination in join buffer {
      if row satisfies join conditions,
      send to client
    }
  }
}
注:注意到一點:是在第二個循環才把數據存在join buffer中,這正好印證了上面的第4點



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章