Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL关联查询Join

MySQL关联查询Join的实现原理和优化建议

作者:JAVA旭阳

在平时的开发过程中,大家应该经常会用到join进行多个表的之间的关联查询,但是如果使用不合理的话,会导致查询性能下降,本文就MySQL中的关联查询的实现原理以及一些优化建议等内容做一个讲解,需要的朋友可以参考下

关联查询介绍

关联查询,指两个或更多个表一起完成查询操作。

合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行,语法如下:

SELECT 字段列表
FROM A表 INNER JOIN B表
ON 关联条件
WHERE 等其他子句;

两个表在连接过程中除了返回满足连接条件的行以外,还返回左表中不满足条件的行。

#实现查询结果是A
SELECT 字段列表
FROM A表 LEFT JOIN B表
ON 关联条件
WHERE 等其他子句;

两个表在连接过程中除了返回满足连接条件的行以外,还返回右表中不满足条件的行。

#实现查询结果是B
SELECT 字段列表
FROM A表 RIGHT JOIN B表
ON 关联条件
WHERE 等其他子句;

 

关联查询原理

前面讲解了连接查询的几种方式,现在谈谈MySQL底层是支持这几种连接查询的。

关联查询中涉及到多张表的的查询,根据驱动类型分为驱动表和被驱动表,驱动表就是主表,被驱动表就是从表。我们可以在执行计划中看出来。

了解了驱动表和被驱动表以后,现在我们看下MySQL究竟是怎么做join查询的。

简单嵌套循环连接

简单嵌套循环连接(Simple Nested-Loop join)是从驱动表A中取出一条数据,遍历表B,将匹配到的数据放到result.. 以此类推, 如下图所示:

开销统计简单嵌套循环连接
驱动表扫描次数1
被驱动表扫描次数A
读取记录数A+B*A
JOIN比较次数B*A
回表读取记录次数0

块嵌套循环连接

块嵌套循环连接(Block Nested-Loop Join)是对上面一种算法的优化,竟然逐条的去驱动表中获取数据去匹配,和磁盘IO交互太多了,那么能否批量的方式呢?而这种算法就是借鉴了这样的思想。

不再是逐条获取驱动表的数据,而是一块一块的获取,引入了join buffer缓冲区,将驱动表join相关的部分数据列、缓存到join buffer中,然后全表扫描被驱动表,被驱动表的每一条记录一次性和join buffer中的所有驱动表记录进行匹配(内存中操作),将简单嵌套循环中的多次比较合并成一次,降低了被驱动表的访问频率。整体如下图所示:

开销统计简单嵌套循环连接块嵌套循环连接
驱动表扫描次数11
被驱动表扫描次数AA*used_column_size/join_buffer_size+1
读取记录数A+B*AA+B*(A*used_column_size/join_buffer_size)
JOIN比较次数B*AB*A
回表读取记录次数00
show variables like '%join_buffer%';

索引嵌套循环连接

那还有没有效率更加高的关联查询算法呢?索引嵌套循环连接(Index Nested-Loop Join)就是效率最高的,前提条件是被驱动表的关联字段建立了索引。通过驱动表匹配条件直接与被驱动表的索引进行匹配,避免和内存表的每条记录去进行比较,这样极大的减少了对内存表的匹配次数。如下图所示:

开销统计简单嵌套循环连接块嵌套循环连接索引嵌套循环连接
驱动表扫描次数111
被驱动表扫描次数AA*used_column_size/join_buffer_size+10
读取记录数A+B*AA+B*(A*used_column_size/join_buffer_size)A+B(match)
JOIN比较次数B*AB*AA*Index(Height)
回表读取记录次数00B(match)(if possible)

因为索引查询的成本基本一样,为了降低开销,驱动表是小表更加合适。

Hash Join(MySQL 8)

从MySQL8后面的版本开始废弃块嵌套循环连接,默认使用了Hash Join的方式。

优化建议

前面讲解了关联查询Join的实现原理,那么对于关联查询模式我们可以从中总结出下面的一些优化点:

总结

本文分享了日常工作中使用非常频繁的关联查询,主要关注关联查询的实现原理,这样我们可以在平时写关联查询的SQL时候性能才会更佳。如果本文对你有帮助,请留下一个赞吧。

以上就是MySQL关联查询Join的实现原理和优化建议的详细内容,更多关于MySQL关联查询Join的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文