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

一:Join 的问题?算法

  - 在实际生产中,使用 join 通常会集中在如下两类:sql

    - DBA 不让使用 Join ,使用 Join 会有什么问题呢?数组

    - 若是有两个大小不一样的表作 join,应该用哪一个表作驱动表呢?oop

 

二:数据准备spa

  • 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) (被驱动表有索引的状况选择)code

  - 语句xml

    - 为了不Mysql选择驱动表对于分析的影响,改用 straight_join 让 MySQL 使用固定的链接方式执行查询。blog

    - 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 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该做为驱动表。

相关文章
相关标签/搜索