MySQL Join的实现原理及优化思路

一、Join的实现原理

在MySQL中,只有一种Join算法,就是大名鼎鼎的Nested Loop Join,他没有其他很多数据库所提供的Hash Join,也没有Sort Merge Join。顾名思义,Nested Loop Join实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参与Join,则再通过前两个表的Join结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复。

MySQL 8.0支持Hash Join了。

二、Join语句的优化

1、尽可能减少Join语句中的Nested Loop的循环总次数
如何减少Nested Loop的循环总次数?最有效的办法只有一个,那就是让驱动表的结果集尽可能的小,这也正是优化基本原则之一“永远用小结果集驱动大的结果集”。

2、优先优化Nested Loop的内层循环
不仅仅是在数据库的Join中应该做的,实际上在我们优化程序语言的时候也有类似的优化原则。内层循环是循环中执行次数最多的,每次循环节约很小的资源,在整个循环中就能节约很大的资源。

3、保证Join语句中被驱动表上Join条件字段已经被索引
保证被驱动表上Join条件字段已经被索引的目的,正是针对上面两点的考虑,只有让被驱动表的Join条件字段被索引了,才能保证循环中每次查询都能够消耗较少的资源。

4、当无法保证被驱动表的Join条件字段被索引且内存资源充足的前提下,不要太吝惜Join Buffer的设置
当在某些特殊的环境中,我们的Join必须是All,Index,range或者是index_merge类型的时候,Join Buffer就会派上用场了。在这种情况下,Join Buffer的大小将对整个Join语句的消耗起到非常关键的作用。

三、Join Buffer是什么
某些情况下,join关联字段没有索引。MySQL先取出驱动表数据放在join buffer,然后一行一行取被驱动表和驱动表做比较,匹配到满足条件的行则作为结果集的一部分,一直到完成全表扫描。
如果驱动表非常大,join buffer放不下,那么一次就只能取一部分,然后取被驱动表数据进行比较,完成之后取下一部分。

参考资料:
https://www.modb.pro/db/61711