mysql join原理剖析

基础

我先简单介绍下 join,主要分为

  • 内连接:驱动表中的记录在被驱动表中没有匹配的记录,不需要加到结果集;

  • 外连接:驱动表中的记录在被驱动表中没有匹配的记录,需要加到结果集中,用 null 代替。

  • 内连接mysql会选择扫描次数比较少的作为驱动表,where 和 on 子句是等价的。

  • 左外连接左侧表为驱动表,右外连接右侧表为驱动表,左右外连接驱动表和被驱动表不能轻易互换。

  • 外表也称为驱动表,内表也称为被驱动表

原理

然后再说下 join 的原理,join 内部主要有三种算法:

Simple Nested-Loop Join(简单嵌套循环连接)

从表A中取出一条数据,遍历表B,将匹配的结果放到result中。这样效率比较低,表A表数据100条,表B表数据1000条,需要遍历10W条;

Index Nested-Loop Join(索引嵌套循环连接)

优化思路是减少内表数据的匹配次数。要求被驱动表上必须有索引,通过外层表的条件直接与内层索引进行匹配,避免和内表的每条数据作比较,减少内层表匹配次数。

Block Nested-Loop Join(块嵌套循环连接)

为了在不存在索引的情况下 算法不退化成Simple~,引入 Block~。不再逐条获取驱动表数据,而是一块块获取,然后批量对比,减小内表【被驱动表】循环次数(内表数据一次性和join_buffer中多条外表数据做对比)。join_buffer 大小由join_buffer_size设定,默认值为256k。

这种算法对系统影响有三个方面:

  1. 可能多次多次扫描被驱动表,占用磁盘IO;

  2. 判断 Join条件需要执行 M*N次对比,占用较多 CPU资源;

  3. 可能导致 buffer_pool 的热数据淘汰,降低缓存命中率。

关键点及优化

最后说下,join 的一些关键点及优化

关键点

  • 所有参与的列都会保存到 join_buffer 中,并不是只有 join 的列

  • 每次join都需要分配一次Join Buffer(N张表需要join,N-1次分配)

  • left是左边是驱动表,right是右边是驱动表。小表【两个表按照各自的条件过滤,过滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是"小表"】驱动大表

优化

  • MRR 优化:避免回表查询在两个数据页之间反复横跳 ,在从二级索引遍历数据获得主键id回表查询完整数据时,先将获取到的主键id放入一个read_rnd_buffer_size中,排序,然后顺序去主键树上获取完整数据,并返回结果。 如果read_rnd_buffer 不够,则会放满后便去主键树查询,然后返回结果,然后再去二级索引上获取主键id。在执行计划中,可以看到 using MRR。

  • BKA优化:为了在NLJ算法中用到 MRR 优化(NLJ算法中驱动表中的数据是一条一条取得,再去被驱动表中匹配用不上MRR )在驱动表中取数据时批量去取。

相关推荐
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
dessler3 小时前
Docker-run命令详细讲解
linux·运维·后端·docker
Q_19284999063 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
Yuan_o_4 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
程序员一诺5 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
DT辰白5 小时前
如何解决基于 Redis 的网关鉴权导致的 RESTful API 拦截问题?
后端·微服务·架构