《Mysql - 到底可不可以使用 Join ?》


一:Join 的問題?

  - 在實際生產中,使用 join 一般會集中在以下兩類:

    - DBA 不讓使用 Join ,使用 Join 會有什么問題呢?

    - 如果有兩個大小不同的表做 join,應該用哪個表做驅動表呢?

 

二:數據准備

  • CREATE TABLE `t2` (
      `id` int(11) NOT NULL,
      `a` int(11) DEFAULT NULL,
      `b` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`)
    ) ENGINE=InnoDB;
    
    CREATE TABLE `t1` (
      `id` int(11) NOT NULL,
      `a` int(11) DEFAULT NULL,
      `b` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`)
    ) ENGINE=InnoDB;

    - 建立 t1,t2 兩個完全相同的表t1 表中寫入 100 條數據,t2 表中 寫入 1000 條數據。

 

三:Index Nested-Loop Join(NLJ) (被驅動表有索引的情況選擇)

  - 語句

    - 為了避免Mysql選擇驅動表對於分析的影響,改用 straight_join 讓 MySQL 使用固定的連接方式執行查詢。

    - t1 是驅動表,t2 是被驅動表。

    - select * from t1 straight_join t2 on (t1.a=t2.a);

 

  - 執行流程

    - 在這條語句里,被驅動表 t2 的字段 a 上有索引,join 過程用上了這個索引

    - 從表 t1 中讀入一行數據 R

    - 從數據行 R 中,取出 a 字段到表 t2 里去查找

    - 取出表 t2 中滿足條件的行,跟 R 組成一行,作為結果集的一部分;

    - 重復執行步驟 1 到 3,直到表 t1 的末尾循環結束。 

    - 

 

  - 小結

    - 這個過程是先遍歷表 t1,然后根據從表 t1 中取出的每行數據中的 a 值,去表 t2 中查找滿足條件的記錄。

    - 在形式上,這個過程很像寫程序時的嵌套查詢類似,並且可以用上被驅動表的索引,所以我們稱之為“Index Nested-Loop Join”,簡稱 NLJ。 

    - 整個過程, 總掃描行數是 200(t1 200 + t2 索引樹200)

 

四:Block Nested-Loop Join(NLJ)(被驅動表無索引選擇)

  - 語句

    -  select * from t1 straight_join t2 on (t1.a=t2.b);

    - 由於表 t2 的字段 b 上沒有索引因此在執行流程時,每次到 t2 去匹配的時候,就要做一次全表掃描。

 

  - 流程

    - 把表 t1 的數據讀入線程內存 join_buffer 中,由於我們這個語句中寫的是 select *,因此是把整個表 t1 放入了內存;

    - 掃描表 t2,把表 t2 中的每一行取出來,跟 join_buffer 中的數據做對比,滿足 join 條件的,作為結果集的一部分返回。

    - 

 

  - 小結

    - 可以看到,在這個過程中,對表 t1 和 t2 都做了一次全表掃描,因此總的掃描行數是 1100。

    - 由於 join_buffer 是以無序數組的方式組織的,因此對表 t2 中的每一行,都要做 100 次判斷,總共需要在內存中做的判斷次數是:100*1000=10 萬次。

    - join_buffer 的大小是由參數 join_buffer_size 設定的,默認值是 256k。如果放不下表 t1 的所有數據話,策略很簡單,就是分段放。

 

五:總結

  - 能不能使用 join ?

    - 如果可以使用 Index Nested-Loop Join 算法,也就是說可以用上被驅動表上的索引,其實是沒問題的;

    - 如果使用 Block Nested-Loop Join 算法,掃描行數就會過多。

      - 尤其是在大表上的 join 操作,這樣可能要掃描被驅動表很多次,會占用大量的系統資源。所以這種 join 盡量不要用。

 

  - 如果要使用 join,應該選擇大表做驅動表還是選擇小表做驅動表?

    - 在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過濾完成之后,計算參與 join 的各個字段的總數據量,數據量小的那個表,就是“小表”,應該作為驅動表。


免責聲明!

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



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