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