Skip to content

多表查询

连接的过程

  1. 首选确定第一个需要查询的表,这个表被称为驱动表(基于单表查询代价最小的表)。根据条件过滤驱动表数据。驱动表只会被查询一次。
  2. 根据驱动表查询的每一条记录依次去被驱动表中寻找匹配的记录。驱动表有多少条符合条件的数据,被驱动表就会被访问几次。

连接的类型

sql
# 内连接
SELECT A.*, B.* FROM A,B WHERE A.id = B.id;
# 左外连接
SELECT A.*, B.* FROM A LEFT JOIN B ON A.id = B.id WHERE A.age > 10;
# 右外连接
SELECT A.*, B.* FROM A RIGHT JOIN B ON A.id = B.id WHERE A.age > 10;

如果是超过两张表的连接,那么先连接两张表,再将两张表的结果作为新的驱动表执行连接操作。

连接的原理

循环嵌套连接

驱动表只访问一次,但被驱动表却可能被多次访问,访问次数取决于对驱动表执行单表查询后的结果集中的记录条数的连接执行方式称之为嵌套循环连接Nested-Loop Join

  • 步骤1:选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询。
  • 步骤2:对上一步骤中查询驱动表得到的结果集中每一条记录,都分别到被驱动表中查找匹配的记录。

我们可以通过给被驱动表添加索引来实现快速连接,因为被驱动表可能会访问多次。

基于块的连接

循环嵌套连接中,每次匹配都是驱动表拿出一条记录,然后从被驱动表中取出记录加载到内存中,然后被驱动表的记录和这一条驱动表记录进行比对,然后从内存中清除被驱动表记录。再拿出驱动表的另一条记录,再将被驱动表的记录加载到内存中进行比对,所以有多少条驱动表记录,那么被驱动表就会被加载到内存中多少次。

块连接是基于join buffer的嵌套连接算法。

join buffer是在执行连接查询前申请的一块固定大小的内存,先把若干条驱动表结果集中的记录装在这个join buffer中,然后开始扫描被驱动表,每一条被驱动表的记录一次性和join buffer中的多条驱动表记录做匹配。

假设A表和B表进行基于块的连接查询,那么A表会根据A的条件进行单表查询(不包含关联条件),将结果放入join buffer,再执行B表的条件查询(不包含关联条件),将结果放入join buffer中,在内存中进行匹配,执行一批后再进行下一批,如此往复。

join buffer通过参数join_buffer_size设置,默认262144字节(256k)。需要注意的是驱动表的记录并不是所有列都会被放到join buffer中,只有查询列表中的列和过滤条件中的列才会被放到join buffer中,所以连接查询中我们不要用*作为查询列,这样可以将更多的表记录放到join buffer中。