MySQL如何执行关联查询

MySQL中关联一次意义比较广泛,并不仅仅是一个查询需要到2个表匹配才叫关联,而是任何一个查询都是一次关联,每一个查询,片段(包括子查询单表的查询)都可能是关联

当前 MySQL 关联执行策略很简单:MySQL 对任何关联都执行嵌套循环关联操作,即 MySQL 现在一个表中循环取出单条数据,然后再嵌套到下一个表中寻找匹配的行,依次下去,直到找到所有表中匹配的行为止。然后根据各个表匹配的行,返回查询中需要的各个列。MySQL 会尝试在最后一个关联表中找到所有匹配的行,如果最后一个关联表无法找到更多的行以后,MySQL 返回到上一次关联表,看是否能够找到更多匹配记录,依次迭代执行

按照这样的方式查找第一个表记录,再嵌套查询下一个关联表,然 后回溯到上一个表,在MySQL中是通过嵌套循环的方式实现——正如 其名 嵌套循环关联

mysql> select tbl1.col1,tbl2.col2  
	   from tbl1 inner join tbl2 using(col3) 
	   where tbl1.col1 in(5,6);

假设mysql按照查询中的表顺序进行关联操作,我们则可以用下面的伪代码表示mysql将如何完成这个查询:

outer_iter = iterator_over tbl1 where col1 in(3,4)
outer_row = outer_iter.next
    while outer_row
    inner_iter = iterator over tbl2 where col3=outer_row.col3
    inner_row = inner_iter.next
    while inner_row
     output[outer_row.col1,inner_row.col2]
        inner_row = inner_iter.next
     end
     out_row = outer_iter.next
end

上面的执行计划对于单表查询和多表关联查询都适用,如果是一个单表查询,那么只需要完成上面的外层的基本操作。对于外连接和上面的执行过程任然适用。例如我们将上面的查询修改如下:

mysql> SELECT tbl1.col1 ,tbl2.col2 FROM tbl1 
		left outer join tbl2 using (col3)
		WHERE tbl1.col1 in (3,4)

伪代码

outer_iter = iterator over tbl1 where col1 in(3,4)
outer row = outer_iter.next
while outer_row
    inner_iter = iterator over tbl2 where col3 = outer_row.col3
    inner_row = inner_iter.next
    if inner row   
        while inner_row
            out_put [outer_row.col1,inner_row.col2]
            inner_row = inner_iter.next
        end
    else         
        out_put[outer_row.col1,NULL]         
    end
    outer_row = outer_iter.next
end

另一种可视化查询执行计划的方法是根据优化器执行的路径绘制出 对应的“泳道图”请从左至右,从上至下地看这幅图。

mysql夺标关联update mysql关联条件查询_数据库

从本质上说,MySQL对所有的类型的查询都以同样的方式运行。 例如,MySQL在FROM子句中遇到子查询时,先执行子查询并将其结果 放到一个临时表中,然后将这个临时表当作一个普通表对待(正如 其名“派生表”)。MySQL在执行UNION查询时也使用类似的临时表,在遇到右外连接的时候,MySQL将其改写成等价的左外连接。简而言之,当前版本的MySQL会将所有的查询类型都转换成类似的执行计划

不过,不是所有的查询都可以转换成上面的形式。例如,全外连接 就无法通过嵌套循环和回溯的方式完成,这时当发现关联表中没有找到 任何匹配行的时候,则可能是因为关联是恰好从一个没有任何匹配的表 开始。这大概也是MySQL并不支持全外连接的原因。还有些场景,虽 然可以转换成嵌套循环的方式,但是效率却非常差

MySQL 生成查询的一颗指令树,然后通过存储引擎执行完成这颗指令树big返回结果,任何多表查询都可以使用一棵树表示

mysql夺标关联update mysql关联条件查询_数据库_02

在计算机科学中,这被称为一颗平衡树。但是,这并不是MySQL 执行查询的方式。正如我们前面章节介绍的,MySQL总是从一个表开 始一直嵌套循环、回溯完成所有表关联。所以,MySQL的执行计划总是一棵左测深度优先的树

mysql夺标关联update mysql关联条件查询_嵌套循环_03

mysql> explain select u.id,c.id from sys_user u left join sys_area  c on c.id = u.city_id where u.id > 3;


+----+-------------+-------+------------+--------+---------------+---------+---------+--------------+------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref          | rows | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+--------------+------+----------+-------------+
|  1 | SIMPLE      | u     | NULL       | range  | PRIMARY       | PRIMARY | 8       | NULL         |   10 |   100.00 | Using where |
|  1 | SIMPLE      | c     | NULL       | eq_ref | PRIMARY       | PRIMARY | 8       | hr.u.city_id |    1 |   100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+--------------+------+----------+-------------+
2 rows in set (0.06 sec)

可以看出,首先在 sys_user 表上进行范围查询,筛选出 u.id > 3 的数据,然后在进行"嵌套查询"。