mysql两表连接原理(搞懂join buf)

622 阅读3分钟

概述

一般情况下,我们使用mysql都是使用两种查询比较多,一个是单表查询,一个是多表连接。多表连接原理还是很重要的,特别是对查询优化这块的理解。多表连接就要考虑怎么连接比较合理,这就要知道连接的原理了。

原理

1.正常情况下表连接

image.png

1.两张表 stu 和stu_score,也就是一张记录学生基本信息表,一张记录学生成绩表

2.现在需要join 两张表,假设 on 条件为 stu.id=stu_score.stu_id作为连接条件
  
3.基于stu作为驱动表,从id等于1的记录开始,那么我图中画出来stu_score的只是
 聚簇索引,但是连接条件是stu_score.stu_id,那么只能扫描聚簇索引,这里stu
 有五条记录,那么全扫描stu表一次,每条记录为了连接,需要到stu_score扫描一次
 那么就要扫描stu_score五次。那么总成本就是stu扫描一次,stu_score扫描五次
 
4.依然是stu作为驱动表,从stu开始扫描进行连接,这次假设stu_score.stu_id建立
 了二级索引,那么每次查找某个stu_score的记录进行连接不需要全表扫描,至少
 都是ref访问级别的。那么总成本就是stu扫描一次,stu_score ref五次

2.mysql真实表连接

image.png

1.依然是基于stu表作为驱动表,这次先会将满足条件的驱动表记录一次性查出来,
  然后放入到join buf中。
  
2.stu_score.stu_id没有建立二级索引情况下,直接一次性扫描stu_score表,然后
  和join buf的记录直接全部连接,那么直接join好了所有记录。那么成本就是stu扫描一次,
  stu_score扫描一次
  
3.stu_score.stu_id建立二级索引情况下,ref方法访问stu_score表,然后
  和join buf的记录进行一条条连接,那么直接join好了所有记录。那么成本就是stu扫描一次,
  stu_score扫描一次(ref级别)  

为什么需要join buf

mysql数据加载原理:
  1.单表中当我们执行一条查询语句是怎么加载表空间数据呢?比如我们要id=10,那么mysql就直接
    去索引中查找,然后把含有id=10的记录的页,从表空间(磁盘文件)把这个页加载出来,
    innodb是按照16k的页为单位加载到内存,然后页内搜索,返回相应记录。
    
  2. 多表中,当我们执行一条连接语句查询时候,那么只能驱动表查询一个页的某些记录,然后根据
     连接条件到被驱动表中进行扫描表连接,周而复始这样操作。

join buf出现:
   连接表时,将驱动表中数据从每次加载的页中,分别加载出来,然后一次性把记录存入join buf,
   这样就能达到被驱动表和驱动表多条记录同时join的机会了,这样join次数就变成一次了。比如
   上面stu表作为驱动表,我们看到有两页数据需要join,那么就不用一页一页去join了,全部加载
   到join buf一次join就好了。

总结

1.大概连接原理就是,先单表访问(过滤条件加索引)驱动表,然后将驱动表记录加入到join buf,
  接着扫描(加索引,提高扫描效率)被驱动表,直接将记录加载出来和join buf记录连接,连接
  完成。
  
2.我们优化join基本上需要注意几点:
  a.单表访问驱动表加索引,快速加载到join buf
  b.join buf 大小选择注意,并不是每次都能一次把所有驱动表记录加载进去
  c.被驱动表连接条件加上索引,这样扫描被驱动表每次方法就不会是all
  
3.扫描表==多次ref,注意我这里扫描一次被驱动表的概念