连接的本质就是把各个连接表中的记录都取出来依次匹配的组合加入结果 集并返回给用户。

驱动表与被驱动表

  • 第一个需要查询的表,称为驱动表
  • 根据 e1 表中的记录去找 e2 表中的记录,e2 表也被称之为被驱动表
  • 在两表连接查询中,驱动表只需要访问一次,被驱动表可能被访问多次
    1. SELECT * FROM e1, e2 WHERE e1.m1 > 1 AND e1.m1 = e2.m2 AND e2.n2 < 'd';

    image.png**

Mysql对连接查询的优化

1.嵌套循环连接(Nested-Loop Join)

如果有 3 个表进行连接的话,那么首先两表连接得到的结果集就像是新的驱 动表,然后第三个表就成为了被驱动表。这个过程就像是一个嵌套的循环,所以这种驱动表只访问一次,但被驱动表 却可能被多次访问,访问次数取决于对驱动表执行单表查询后的结果集中的记录 条数的连接执行方式称之为嵌套循环连接(Nested-Loop Join),这是最简单, 也是最笨拙的一种连接查询算法,时间复杂度是 O(NML)。

2.使用索引加快连接速度

对应explain中的ref 与eq_ref

3.基于块的嵌套循环连接(Block Nested-Loop Join)

以 MySQL 提出了一个 join buffer 的概念,join buffer 就是执行连接查询前申请 的一块固定大小的内存,先把若干条驱动表结果集中的记录装在这个 join buffer 中,然后开始扫描被驱动表,每一条被驱动表的记录一次性和 join buffer 中的多条驱动表记录做匹配,因为匹配的过程都是在内存中完成的,所以这样可以显著 减少被驱动表的 I/O 代价。 :::tips join buffer 中存的是驱动表的数据! ::: 最好的情况是 join buffer 足够大,能容纳驱动表结果集中的所有记录。 这种加入了 join buffer 的嵌套循环连接算法称之为基于块的嵌套连接(Block Nested-Loop Join)算法。 这个 join buffer 的大小是可以通过启动参数或者系统 变量 join_buffer_size 进 行配置,默认大小为 262144 字节(也就是 256KB),最小可以设置为 128 字节。
当然,对于优化被驱动表的查询来说,最好是为被驱动表加上效率高的索引, 如果实在不能使用索引,并且自己的机器的内存也比较大可以尝试调大 join_buffer_size 的值来对连接查询进行优化。
另外需要注意的是,驱动表的记录并不是所有列都会被放到 join buffer 中, 只有查询列表中的列和过滤条件中的列才会被放到 join buffer 中,所以再次提醒 我们,最好不要把*作为查询列表,只需要把我们关心的列放到查询列表就好了, 这样还可以在 join buffer 中放置更多的记录。