mysql join语句的执行流程是怎么样的

mysql join语句的执行流程是怎么样的

join语句是使用十分频繁的sql语句,同样结果的join语句,写法不同会有非常大的性能差距。

select * from t1 straight_join t2 on (t1.a=t2.a);a字段都有索引

  1. TRAIGHT_JOIN语法能指定使用左边的表作为join语句的驱动表,join是让执行器自动选择。以上语句会选择t1作为驱动表。
  2. join语句,mysql内部执行时候会采用2中算法。一个是NLJ(Index Nested-Loop Join)。一个是BNL(Block Nested-Loop Join)
  3. NLJ:在join语句执行过程中,如果可以使用到被驱动表的索引,我们称之为”Index Nested-Loop Join”,简称 NLJ。
  4. 驱动表是走全表扫描,而被驱动表是走树搜索,所以驱动表行数越小越好。扫描行数多,性能影响更大,因此应该让小表来做驱动表。
  5. 如果驱动表有索引,被驱动表没有索引,这种情况下,驱动表全表扫描后,去被驱动表中匹配where语句的条件,在被驱动表找一条数据又是全表扫描。这样整个join扫描行数会内指数级别扩大。这种叫”Simple Nested-Loop Join”算法。
  6. 基于第五点,这种情况太笨重。所以msql没有采用”Simple Nested-Loop Join”算法,而是叫”Block Nested-Loop Join”的算法,简称 BNL。被驱动表没有索引情况下,他的逻辑流程是这样的:
  7. 把表 t1 的数据读入线程内存 join_buffer 中,由于我们这个语句中写的是 select *,因此是把整个表 t1 放入了内存;
    mysql join语句的执行流程是怎么样的
  8. explain语句查询出来会有 use join buffer (block nested loop)关键字
  9. join语句采用BNL算法,虽然对表 t1(100行) 和 t2(1000行) 都做了一次全表扫描,因此总的扫描行数是1100。由于 join_buffer 是以无序数组的方式组织的,因此对表 t2 中的每一行,都要做 100 次判断,总共需要在内存中做的判断次数是:100*1000=10 万次。对比simple Nested-Loop Join算法他是在内存中做对比计算。能大大提供性能。
  10. join_buffer 的大小是由参数 join_buffer_size设定的,默认值是 256k。如果放不下表 t1 的所有数据话,策略很简单,就是分段放。就是放多少先处理多少先作为结果集返回,然后清空join_buffer,继续读取后面的数据。
  11. 所以考虑到join_buffer大小有限,让小表作为驱动表,分段情况下,分段次数少。也应该让小表作为驱动表。
  12. 在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是”小表”,应该作为驱动表。 join语句优化:
  13. mysql在join语句时,内部做了一些优化,即:Multi-Range Read 优化 (MRR)。这个优化的主要目的是尽量使用顺序读盘。原理是:mysql的索引数据目录中,都是有序的,我们读入数据后,按主键排下序。这样就极大可能在磁盘是顺序读盘。这引入了read_rnd_buffer ,它的大小是由 read_rnd_buffer_size 参数控制的。
  14. 如果你想要稳定地使用 MRR 优化的话,需要设置set optimizer_switch=”mrr_cost_based=off”。(官方文档的说法,是现在的优化器策略,判断消耗的时候,会更倾向于不使用 MRR,把 mrr_cost_based 设置为 off,就是固定使用 MRR 了。)explain语句也会有 use MRR关键字
  15. 在使用BNL算法时候,引擎是一行一行读取数据。这样就用不上MRR算法优化,所以采取了BKA (Batched Key Access)算法。他可以一次性从驱动表多读一些数据,这些数据临时放在join_buff中。(之前BNL算法用不上join_buff,就利用了这个空间)。
    mysql join语句的执行流程是怎么样的
  16. 如果 join buffer 放不下 P1~P100 的所有数据,就会把这 100 行数据分成多段执行上图的流程。如果要使用 BKA 优化算法的话,你需要在执行 SQL 语句之前,先设置 set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';前两个参数的作用是要启用 MRR。这么做的原因是,BKA 算法的优化要依赖于 MRR。
  17. BNL算法数据太大,稍不主机就会极大影响mysql服务性能,导致Buffer Pool命中率变低。大表 join 操作虽然对 IO 有影响,但是在语句执行结束后,对 IO 的影响也就结束了。但是,对 Buffer Pool 的影响就是持续性的,需要依靠后续的查询请求慢慢恢复内存命中率。
  18. BNL 算法对系统的影响主要包括三个方面:
    1. 可能会多次扫描被驱动表,占用磁盘 IO 资源;
    2. 判断 join 条件需要执行 M*N 次对比(M、N 分别是两张表的行数),如果是大表就会占用非常多的 CPU 资源;
    3. 可能会导致 Buffer Pool 的热数据被淘汰,影响内存命中率。
  19. BNL算法优化:
    1. BNL 转 BKA算法,在驱动表和被驱动表建索引,如果不方便建索引(数据大,join语句不频繁),可以人工主动使用临时表中转,拆分多个语句转化成BKA算法。
    2. hash join。条件匹配是n x m级别计算,如果 join_buffer 里面维护的不是一个无序数组,而是一个哈希表的话,那么就不是 10 亿次判断,而是 100 万次 hash 查找。mysql不支持哈希 join。并且,MySQL 官方的 roadmap,也是迟迟没有把这个优化排上议程。备注:mysql8.0已经支持

执行流程:

  1. 从表 t1 中读入一行数据 R;
  2. 从数据行 R 中,取出 a 字段到表 t2 里去查找;
  3. 取出表 t2 中满足条件的行,跟 R 组成一行,作为结果集的一部分;
  4. 重复执行步骤 1 到 3,直到表 t1 的末尾循环结束。

mysql join语句的执行流程是怎么样的

Original: https://www.cnblogs.com/penngke/p/15410221.html
Author: penngke
Title: mysql join语句的执行流程是怎么样的

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/586006/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • RabbitMQ知识简单理解

    官网链接:http://next.rabbitmq.com/getstarted.html 官网给出了每种工作模式的实例代码,可以参考其中的实现 一、RabbitMQ整体架构图 二…

    Linux 2023年6月14日
    0107
  • 2-第一个Django程序

    第一个Django程序 从本章节开始将通过实现一个投票应用程序,来让用户逐步的了解Django。这个程序由两步分组成: 公共站点,允许用户访问进行投票,和查看投票。 站点管理,允许…

    Linux 2023年6月7日
    0100
  • [20220106]ora-00600 kokasgi1.txt

    [20220106]ora-00600 kokasgi1.txt –//上午看了https://www.xifenfei.com/2022/01/2022-first-…

    Linux 2023年6月13日
    085
  • CentOS 文本编辑器

    Linux 终端的文本编辑器中,较著名的有:Nano、Vim、Emacs。其它文本编辑器还有 Gedit、Sublime,Atom 等等。 1.1、基础命令 nano:打开 nan…

    Linux 2023年6月8日
    0108
  • PHP array_values()

    array_values array_values() 函数返回一个包含给定数组中所有键值的数组,但不保留键名。 示例: function arrayValues() { $dat…

    Linux 2023年6月7日
    092
  • MySQL备份与恢复

    MySQL备份与恢复 备份是数据安全的最后一道防线,对于任何数据丢失的场景,备份虽然不一定能恢复百分之百的数据(取决于备份周期),但至少能将损失降到最低。 数据丢失的场景举例: 人…

    Linux 2023年6月7日
    0165
  • 排查线上问题的9种方式

    德国科技管理专家斯坦门茨早年移居美国,他以非凡的才能成为美国企业界的佼佼者。一次,美国著名的福特公司的一组电机发生故障,在束手无策之时,公司请斯坦门茨出马解决问题。 斯坦门茨在电机…

    Linux 2023年6月14日
    088
  • Base-64字符串无效,The input is not a valid Base-64 string as it contains a non-base 64 character

    base64规则: 字符串只可能包含A-Z,a-z,0-9,+,/,=字符 字符串长度是4的倍数 =只会出现在字符串最后,可能没有或者一个等号或者两个等号 首先,C# 做上传文件的…

    Linux 2023年6月7日
    0106
  • Linux 常用目录管理命令

    cp:复制文件或目录,直接复制,如,cp /root/install.sh /home cp -a:相当於 -pdr 的意思,至於 pdr 请参考下列说明;(常用),如 cp -a…

    Linux 2023年6月14日
    093
  • batch批处理笔记

    1. echo 和 @ 回显命令 @ #关闭单行回显 echo off #从下一行开始关闭回显 @echo off #从本行开始关闭回显。一般批处理第一行都是这个 echo on …

    Linux 2023年6月7日
    082
  • BKT的胡测题解:第一套第二题reactor

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/Grharris/p/11530297.htmlAuth…

    Linux 2023年6月6日
    085
  • git 的使用

    git 的使用 1、介绍 代码版本管理、协同开发 对文件(代码)进行版本管理 完成协同开发 项目,帮助程序员整合代码 i)帮助开发者合并开发的代码 ii)如果出现冲突代码的合并,会…

    Linux 2023年6月14日
    087
  • Redis 缓存穿透、雪崩、击穿以及相关解决方案

    缓存流程: 缓存穿透: 什么是缓存穿透:是指 redis 和数据库都没有这个数据,大量请求该数据造成数据库挂掉,该请求一般是非正常用户 解决方案: 布隆过滤器:将数据库中所有的查询…

    Linux 2023年5月28日
    075
  • 用redis解决多用户同时编辑同一条数据问题

    1,场景再现 场景:总公司可以给分公司下发今年的规划任务(可能只是写了个规划大纲),分公司收到后,进行详细的规划补充,然后提交。 比如规划表: CREATE TABLE sys_p…

    Linux 2023年5月28日
    076
  • k8安装

    1.安装k8s之前需要安装docker,etcd 因为要在k8s的pod中运行容器,需要先安装 容器运行时(Container Runtimes ) 几种常见的容器运行时与 Kub…

    Linux 2023年6月13日
    087
  • OrchardCore Headless建站拾遗

    书接上回,OrchardCore的基本设置写了,但是有一说一,这个东西还是挺复杂的,如果需要构建一个简单的企业网站,还需要干点别的活。 本文考虑在尽量少编程的基础上,完成一个Hea…

    Linux 2023年6月6日
    090
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球