mybatisplus多表关联查询_神奇的SQL:探索多表连接查询的执行细节

2023-10-27

作者:jb_hz

来源:https://blog.csdn.net/qq_27529917/

先构建本篇博客的案列演示表:

1.驱动表如何选择?

驱动表的概念是指多表关联查询时,第一个被处理的表,使用此表的记录去关联其他表。驱动表的确定很关键,会直接影响多表连接的关联顺序,也决定了后续关联时的查询性能。

驱动表的选择遵循一个原则:在对最终结果集没影响的前提下,优先选择结果集最小的那张表作为驱动表。改变驱动表就意味着改变连接顺序,只有在不会改变最终输出结果的前提下才可以对驱动表做优化选择。

在外连接情况下,很多时候改变驱动表会对输出结果有影响,比如left join的左边表和right join的右边表,驱动表选择join的左边或者右边最终输出结果很有可能会不同。

用结果集来选择驱动表,那结果集是什么?如何计算结果集?mysql在选择前会根据where里的每个表的筛选条件,相应的对每个可作为驱动表的表做个结果记录预估,预估出每个表的返回记录行数,同时再根据select里查询的字段的字节大小总和做乘积:

每行查询字节数 * 预估的行数 = 预估结果集

通过where预估结果行数,遵循以下规则:

  • 如果where里没有相应表的筛选条件,无论on里是否有相关条件,默认为全表
  • 如果where里有筛选条件,但是不能使用索引来筛选,那么默认为全表
  • 如果where里有筛选条件,而且可以使用索引,那么会根据索引来预估返回的记录行数

我们以上述创建的表为基础,用如下sql作为案列来演示:

select a.*,c.c2 from a join c on a.a2=c.c2 where a.a1>5 and c.c1>5;

通过explain查看其执行计划:

explain显示结果里排在第一行的就是驱动表,此时表c为驱动表。

如果将sql修改一下,将select 里的条件c.c2 修改为 c.* :

select a.*,c.* from a join c on a.a2=c.c2 where a.a1>5 and c.c1>5;

通过explain查看其执行计划:

此时驱动表还是c,按理来说 c.* 的数据量肯定是比 a.*大的,似乎结果集大小的规则在这里没有起作用。

此情形下如果用a作为驱动表,通过索引c2关联到c表,那么还需要再回表查询一次,因为仅仅通过c2获取不到c.* 的数据,还需要通过c2上的主键c1再查询一次。而上一个sql查询的是c2,不需要额外查询。同时因为a表只有两个字段,通过a2索引能够直接获得a.* ,不需要额外查询。

综上所述,虽然使用c表来驱动,结果集大一些,但是能够减少一次额外的回表查询,所以mysql认为使用c表作为驱动来效率更高。

结果集是作为选择驱动表的一个主要因素,但不是唯一因素。

2.两表关联查询的内在逻辑是怎样的?

mysql表与表之间的关联查询使用Nested-Loop join算法,顾名思义就是嵌套循环连接,但是根据场景不同可能有不同的变种。

比如Index Nested-Loop join,
Simple Nested-Loop join,
Block Nested-Loop join,
Betched Key Access join等。

  • 在使用索引关联的情况下,有Index Nested-Loop join和Batched Key Access join两种算法;
  • 在未使用索引关联的情况下,有Simple Nested-Loop join和Block Nested-Loop join两种算法;

我们先来看有索引的情形,使用的是博客刚开始时建立的表,sql如下:

select a.*,c.* from a join c on a.a2=c.c2 where a.a1>4;

通过explain查看其执行计划:

首先根据第一步的逻辑来确定驱动表a,然后通过a.a1>4,a.* 来查询一条记录a1=5,将此记录的c2关联到c表,取得c2索引上的主键c1,然后用c1的值再去聚集索引上查询c.*,组成一条完整的结果,放入net buffer,然后再根据条件a.a1>4,a * . 取下一条记录,循环此过程。

过程图如下:

通过索引关联被驱动表,使用的是Index Nested-Loop join算法,不会使用msyql的join buffer。根据驱动表的筛选条件逐条地和被驱动表的索引做关联,每关联到一条符合的记录,放入net-buffer中,然后继续关联。

此缓存区由net_buffer_length参数控制,最小4k,最大16M,默认是1M。如果net-buffer满了,将其发送给client,清空net-buffer,继续上一过程。

通过上述流程知道,驱动表的每条记录在关联被驱动表时,如果需要用到索引不包含的数据时,就需要回表一次,去聚集索引上查询记录,这是一个随机查询的过程。每条记录就是一次随机查询,性能不是非常高。

mysql对这种情况有选择的做了优化,将这种随机查询转换为顺序查询,执行过程如下图:

此时会使用Batched Key Access join 算法,顾名思义,就是批量的key访问连接。

逐条的根据where条件查询驱动表,将符合记录的数据行放入join buffer,然后根据关联的索引获取被驱动表的索引记录,存入read_rnd_buffer。join buffer和read_rnd_buffer都有大小限制,无论哪个到达上限都会停止此批次的数据处理,等处理完清空数据再执行下一批次。也就是驱动表符合条件的数据可能不能够一次处理完,而要分批次处理。

当达到批次上限后,对read_rnd_buffer里的被驱动表的索引按主键做递增排序,这样在回表查询时就能够做到近似顺序查询:

如上图,左边是未排序前的随机查询示意图,右边是排序后使用MRR(Multi-Range Read)的顺序查询示意图。

因为mysql的InnoDB引擎的数据是按聚集索引来排列的,当对非聚集索引按照主键来排序后,再用主键去查询就使得随机查询变为顺序查询,而计算机的顺序查询有预读机制,在读取一页数据时,会向后额外多读取最多1M数据。此时顺序读取就能派上用场。

BKA算法在需要对被驱动表回表的情况下能够优化执行逻辑,如果不需要回表,那么自然不需要BKA算法。

如果要使用 BKA 优化算法的话,你需要在执行 SQL 语句之前先设置:

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

前两个参数的作用是要启用 MRR(Multi-Range Read)。这么做的原因是,BKA 算法的优化需要依赖于MRR,官方文档的说法,是现在的优化器策略,判断消耗的时候,会更倾向于不使用 MRR,把 mrr_cost_based 设置为 off,就是固定使用 MRR 了。)

最后再用explain查看开启参数后的执行计划:

上述都是有索引关联被驱动表的情况,接下来我们看看没有索引关联被驱动表的情况。

没有使用索引关联,那么最简单的Simple Nested-Loop join,就是根据where条件,从驱动表取一条数据,然后全表扫面被驱动表,将符合条件的记录放入最终结果集中。这样驱动表的每条记录都伴随着被驱动表的一次全表扫描,这就是Simple Nested-Loop join。

当然mysql没有直接使用Simple Nested-Loop join,而是对其做了一个优化,不是逐条的获取驱动表的数据,而是多条的获取,也就是一块一块的获取,取名叫Block Nested-Loop join。每次取一批数据,上限是达到join buffer的大小,然后全表扫面被驱动表,每条数据和join buffer里的所有行做匹配,匹配上放入最终结果集中。这样就极大的减少了扫描被驱动表的次数。

BNL(Block Nested-Loop join) 和 BKA(Batched Key Access join)的流程有点类似, 但是没有read_rnd_buffer这个步骤。

示例sql如下:

select a.*, d.* from a join d on a.a2=d.d2  where a.a1>7;

用explain查看其执行计划:

3.多表连接如何执行?是先两表连接的结果集然后关联第三张表,还是一条记录贯穿全局?

其实看连接算法的名称:Nested-Loop join,嵌套循环连接,就知道是多表嵌套的循环连接,而不是先两表关联得出结果,然后再依次关联的形式,其形式类似于下面这样:

对于不同的join方式,有下列情况:

Index Nested-Loop join:

sql如下:

select a.*,b.*,c.* from a join c on a.a2=c.c2 join b on c.c2=b.b2 where b.b1>4;

通过explain查看其执行计划:

其内部执行流程如下:

执行前mysql执行器会确定好各个表的关联顺序。首先通过where条件,筛选驱动表b的第一条记录b5,然后将用此记录的关联字段b2与第二张表a的索引a2做关联,通过Btree定位索引位置,匹配的索引可能不止一条。当匹配上一条,查看where里是否有a2的过滤条件且条件是否需要索引之外的数据,如果要则回表,用a2索引上的主键去查询数据,然后做判断。通过则用join后的信息再用同样的方式来关联第三章表c。

Block Nested-Loop join 和 Batched Key Access join : 这两个关联算法和Index Nested-Loop join算法类似,不过因为他们能使用join buffer,所以他们可以每次从驱动表筛选一批数据,而不是一条。同时每个join关键字就对应着一个join buffer,也就是驱动表和第二张表用一个join buffer,得到的块结果集与第三张表用一个join buffer。

本篇博客主要就是讲述上述三个问题,如何确定驱动表,两表关联的执行细节,多表关联的执行流程。

有疑问欢迎留言,共同进步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mybatisplus多表关联查询_神奇的SQL:探索多表连接查询的执行细节 的相关文章

  • 偶尔连接的 CQRS 系统 - 客户端和服务器命令 - 基于任务的屏幕

    Premise 建议在CQRS DDD ES样式应用程序使用task基于屏幕 这些屏幕引导用户并捕获意图 These task屏幕也可以称为感应式用户界面 UI 设计指南的一些示例可以帮助您创建现代的 用户友好的应用程序 Microsoft
  • Java 中的下载管理器 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要通过 FTP HTTP 从 Java 获取几个大文件 几个演出 有现成的库 java 命令行工具
  • 如何打印Oracle中过程的定义?

    oracle中有没有办法查看过程的结构是什么 我正在尝试记录并运行程序 并希望将实际的程序结构存储在我的日志中 您可以查询ALL SOURCE table SELECT text FROM all source WHERE owner lt
  • 在magento Attributes中添加自定义属性并显示在前端

    我已经开始使用 magento 作为我的电子商务 cms 我知道这是一个非常强大的平台 最近 我发现它的功能可以帮助开发人员扩展核心 并且我已经成功添加了自定义类别选项 是否有机会在某个属性上达到相同的结果 我想在属性选项卡上添加文本描述并
  • 如何将 Terraform 状态从一个远程存储移动到另一个远程存储

    我们使用 Azure blob 存储作为 Terraform 远程状态 并且我尝试将有关特定现有资源的状态信息移动到该存储帐户中的不同容器 新容器 terraforminfra v2 已存在 现有 Terraform 代码指向旧容器 ter
  • html5 canvas 使用图像作为蒙版

    是否可以使用具有形状的图像作为整个画布或画布内图像的蒙版 我想将图像放置在画布中 并在图像上添加蒙版 然后将其另存为新图像 您可以使用 source in globalCompositeOperation 将黑白图像用作蒙版 首先 将蒙版图
  • 解析用户周围的位置

    您好 我开发了一个应用程序 我想问一个问题 在我的数据云解析中 我有 餐馆 类 我有三列 名称 类型字符串 imageFile 类型文件 description 类型数组和 Location 类型GeoPoint 我想知道使用哪种方法来获取
  • 为什么 INT64_MIN 的定义不同?为什么他们的行为不同?

    The stdint h我公司的标题是 define INT64 MIN 9223372036854775808LL 但在我项目的一些代码中 一位程序员写道 undef INT64 MIN define INT64 MIN 92233720
  • Eclipse:如何增加查找/替换历史记录?

    查找 替换对话框显示最后 8 个条目 该对话框通过 Ctrl F 显示 我想增加 查找 和 替换为 输入字段的历史记录中显示的条目数 我必须搜索并替换几个字符串和正则表达式 因此我一次又一次地输入字符串和正则表达式 我并不是指文件内容更改的
  • MVC ASP.NET 或 Razor

    我对 MVC 很陌生 我对 Silver light WPF 和 MVVM 有相当多的了解 但对 MVC 知之甚少 我正在按照 Microsoft 网站上的主要教程进行操作http www asp net mvc tutorials get
  • 重定向到其他控制器中的操作

    我想从一个控制器中的操作重定向到第二个控制器中的操作 通常我会使用 RedirectToAction actionName controllerName objects 我想要重定向到的方法有两个重载 一个用于 HttpVerbs Get
  • 如何将 Hibernate 5 安装到 Apache Karaf v4 中

    我已经安装了 Apache Karaf v4 03 并查询了 Hibernate 的可用功能列表 如下所示 不幸的是 我使用的是 Hibernate v5 hibernate 3 3 2 GA Uninstalled enterprise
  • 从 C/C++ 程序进行 Ping

    我想编写一个 C 或 C 程序 给定一个 IP 地址 对其进行 Ping 然后根据 Ping 是否成功执行进一步的操作 这个怎么做 尽情享受Ping 页面 http www ping127001 com pingpage htm 其中有一个
  • 如何在 Swift 中使用 substringToIndex? [复制]

    这个问题在这里已经有答案了 我在这一行收到编译器错误 UIDevice currentDevice identifierForVendor UUIDString substringToIndex 8 类型 String Index 不符合协
  • 在 MVC4 中使函数异步时 HttpContext.Current null

    我目前正在 VS2010 SP1 中开发 MVC4 我做了其中一个功能 控制器类异步 作为其中的一部分 我制作了控制器类 派生自 AsyncController 并添加了以下两个方法 参见代码部分 1 和 2 下 一种以 Async 结尾的
  • simple_fields_for 没有出现 [rails 4]

    我正在尝试创建两个隐藏字段 其中一个显示没有问题 但来自嵌套表单的另一个则没有 产品 rb class Product lt ActiveRecord Base has many product options dependent dest
  • jsf文件下载不起作用

    当我点击h commandButton它执行myBean dowanlod 方法 但它不下载任何文件 这是我在支持 bean 中的方法 没有例外 光标变得忙碌 似乎在等待响应 对于这种操作是否有任何额外的配置或者这段代码有什么问题吗
  • 如何在 Laravel 中创建一条包罗万象的路线

    我需要一个 Laravelroutes php将捕获所有流量到特定的条目example com premium section网站 以便我可以提示人们在访问优质内容之前成为会员 您还可以通过在参数上使用正则表达式来捕获 全部 Route g
  • IOError:在 Linux 上的 ReportLab 中使用 matplotlib PNG 时“解码器 zip 不可用”,适用于 Windows

    我正在使用 ReportLab 打印 matplotlib 生成的图表 我可以在我的 Windows 开发机器上毫无问题地执行此操作 然而 当我部署到 Ubuntu 服务器时 渲染失败并出现所述错误 我假设我缺少一个 Python 模块 但
  • 使用 TkInter 绑定设置不可交互(点击)覆盖

    我已经浏览了其他几篇关于类似问题的帖子 所有这些似乎都指向this https stackoverflow com questions 29458775 tkinter see through window not affected by

随机推荐

  • GCN代码详解(SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS(2017ICLR))

    不足之处请大家多多指点 文章目录 链接 代码详解 链接 论文题目 用图卷积网络进行自监督分类 GCN 2017ICLR 论文链接 1609 02907v3 pdf arxiv org 代码链接 tkipf pygcn Graph Convo
  • 总链接地址

    链接 达内博客 链接地址 程序媛泡泡 https blog csdn net weixin 43884234 cgblpx 皮皮虾 https blog csdn net u012932876 闪耀太阳 https blog csdn ne
  • python环境离线打包环境、离线环境迁移、离线环境复制、离线环境克隆

    我们经常使用conda来管理自己环境 时间久了 环境中的依赖错综复杂 有的通过pip或者conda下载 有的是离线安装 有的是通过魔法下载 这时候如果要将本机环境复制到另一台计算机中就会非常麻烦 甚至另一台计算机无法联网 这时候可以使用co
  • uni-app简单介绍

    uni app简单介绍 https uniapp dcloud io 一 什么是uni app uni app 是一个使用 Vue js 开发所有前端应用的框架 开发者编写一套代码 可发布到iOS Android Web 响应式 以及各种小
  • 转:Vue项目中的token验证登录(前端部分)

    声明 此文章是转载 2 问题 做一个登录界面 我选择的是用token进行验证登录 我用的前端框架是Vue js 和 element ui 如何在vue 中使用token进行验证登录 3 思考 1 利用token进行验证登录 用户进行登录操作
  • TF卡目录显示文件夹变0字节的方法

    关于电脑上的目录打不开是什么原因 电脑目录打不开是什么原因这个许多人还不清楚 今天小编来为大家解答目录打不开状况 此刻让好多人一起来瞧瞧吧 TF卡目录显示文件夹变0字节的方法 工具 软件 sayRecy 步骤1 先百度搜索并下载程序打开后
  • Python:赋值,copy和deepcopy区别

    参考 Python赋值 copy deepcopy区别 结论 copy 与deepcopy 之间的主要区别是python对数据的存储方式 python2中 需要import copy模块 python3中 直接可以使用copy 方法 但de
  • Postman —— postman实现参数化

    什么时候会用到参数化 比如 一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块 正确的用户名 密码 成功 错误的用户名 正确的密码 失败 postman实现参数化 在实际的接口测试中 部分参数每次发送请求时都要唯一 比如注册
  • jacoco检测功能或自动化测试覆盖率

    参考文档 http t csdn cn QqCSh http t csdn cn HonVL 目录 下载jacoco 启动jacocoagent监控被测项目 执行手工测试 生成exec文件 生成report报告 jacoco代码覆盖率报告分
  • 【Hexo博客搭建】将其部署到GitHub Pages(二):如何初始化并部署?

    系列目录 Hexo博客搭建 将其部署到 GitHub Pages 一 前期要做哪些准备 Hexo博客搭建 将其部署到 GitHub Pages 二 如何初始化并部署 Hexo博客搭建 将其部署到 GitHub Pages 三 怎么写作以及更
  • awr 自动 mail 发送设置

    1 各节点 AWR 自动生成 script 设置 awrrun autoawr sql cat data run awrrun bin sh cd data awrrpt ORACLE HOME u01 product oracle exp
  • Ubuntu 配置 C/C++ 开发环境

    文章目录 0 更新和升级系统软件 1 安装 build essential 软件包 2 安装 gdb 3 安装 cmake 0 更新和升级系统软件 在终端中输入以下命令对软件进行刷新 保证后续安装的软件都是最新的 sudo apt upda
  • 解决微信小程序安卓手机访问不到图片,无法显示图片

    关于微信小程序不显示图片 通病可能有以下几个可能性 非本地图片 确定图片资源存在 copy 图片url再浏览器打开 确定图片资源存在且能正常访问 本地图片 确定相对路径或者绝对路径正确 微信小程序图片路径 不可以存在中文 使用英文做路径和文
  • DataX同步Hive数据丢失,源码修复

    文章目录 DataX简介 DataX 商业版本 DataX的特点 DataX同步Hive数据丢失 DataX的Hive数据源HdfsReader插件 DataX简介 DataX 是阿里云 DataWorks数据集成 的开源版本 在阿里巴巴集
  • 推荐几款好用的压缩软件

    前言 压缩工具作为电脑装机必备软件我们在日常生活中都会经常用到 但是诸如好压 2345 WinRAR等一些常见的压缩软件都会有各种广告弹窗的现象 烦人至极 以下推荐几款免费无广告的强大压缩工具 7 Zip 仅有1M左右的安装包将轻巧便捷阐述
  • [从零开始学习FPGA编程-26]:进阶篇 - 基本组合电路-数据选择器(Verilog语言)

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 前言 第1章 数据选择器 1 1 数据选择器概述与原理
  • 能力和结果之间的关系

    大家好 这里是大话硬件 今天这篇文章想和大家分享前段时间的一点工作体会 关于个人能力和工作结果之间的关系 其实这些感悟是在上周三晚上下班 走在回家的路上 脑海中突然出现这样的体会 回到家里立马写了下来 因为是即时的灵感 完全是因为工作状态触
  • Python有限体积流体开尔文-亥姆霍兹不稳定性

    本文 我们将使用有限体积方法模拟开尔文 亥姆霍兹不稳定性 我们将考虑一种可压缩流体 它具有向背景相反方向移动的高密度流 速度切变引起了著名的不稳定性 有时在云层和木星的大红斑中也可以看到这种不稳定性 有限体积法 我们将描述有限体积法来模拟理
  • 【Web自动化】Python3+Selenium 框架⑸——登录页面类方法

    前言 Selenium是一个用于Web应用程序自动化测试工具 Selenium测试直接运行在浏览器中 就像真正的用户在操作一样 支持的浏览器包括IE 7 8 9 10 11 Mozilla Firefox Safari Google Chr
  • mybatisplus多表关联查询_神奇的SQL:探索多表连接查询的执行细节

    作者 jb hz 来源 https blog csdn net qq 27529917 先构建本篇博客的案列演示表 1 驱动表如何选择 驱动表的概念是指多表关联查询时 第一个被处理的表 使用此表的记录去关联其他表 驱动表的确定很关键 会直接