1. Index Nested-Loop Join

概念解释:

假设有t1,t2两张表,在join连接的时候,t1表驱动t2表,t1走的全部扫描,t2表使用了索引,

则这个时候join就使用了“index nested-loop join”算法,简称:NLJ。

NLJ执行的流程如下:

Index Nested-Loop Join 算法的执行流程

2. Block Nested-Loop Join

基于上面t1表和t2表,join连接,t1表和t2表都没有命中索引,都是走的全部扫描。这个

时候Join使用的是“Block Nested-Loop Join”算法,简称:BNL。

BNL算法的流程如下:

Block Nested-Loop Join 算法的执行流程

在explain分析语句的时候,extra附加信息中会出现“Using join buffer (Block Nested Loop)”。

join_buffer是由参数join_buffer_size决定的。默认是256k。如果放不下表 t1

的所有数据话,策略很简单,就是分段放。

流程大概是:

取t1表的数据,放入join_buffer中,如果join buffer满了,就扫描t2表的数据,跟join buffer

的数据进行对比,满足join条件的作为结果集返回;清空join buffer,继续上面的过程。

能否使用Join?

1. 如果可以使用 Index Nested-Loop Join 算法,也就是说可以用上被驱动表上的索引,

其实是没问题的;

2.  如果使用 Block Nested-Loop Join 算法,扫描行数就会过多。尤其是在大表上的 join

操作,这样可能要扫描被驱动表很多次,会占用大量的系统资源。所以这种 join 尽量不

要用。

如果要使用 join,应该选择大表做驱动表还是选择小表做驱动表?

1. 如果是 Index Nested-Loop Join 算法,应该选择小表做驱动表;

2. 如果是 Block Nested-Loop Join 算法:

在 join_buffer_size 足够大的时候,是一样的;

在 join_buffer_size 不够大的时候(这种情况更常见),应该选择小表做驱动表。

这个问题的结论就是,总是应该使用小表做驱动表。

注意:join慢的时候,尽量跳大join_buffer_size的值。

优化Join

1. 优化NLJ算法

Multi-Range Read 优化算法 (MRR)。这个优化的主要目的是尽量使用顺序读盘。

如果随着辅助索引(二级索引) a 的值递增顺序查询的话,主键索引id 的值就变成随机的,

那么就会出现随机访问,性能相对较差。虽然“按行查”这个机制不能改,但是调整查询的顺序,

还是能够加速的。这就是 MRR 优化的设计思路。

加入了MRR优化的执行流程如下:

1. 根据索引 a,定位到满足条件的记录,将 id 值放入 read_rnd_buffer 中 ;

2. 将 read_rnd_buffer 中的 id 进行递增排序;

3. 排序后的 id 数组,依次到主键 id 索引中查记录,并作为结果返回。

read_rnd_buffer 的大小是由 read_rnd_buffer_size 参数控制的。

启用MRR算法:

set optimizer_switch="mrr_cost_based=off"

Batched Key Access (BKA) 算法

MySQL 在 5.6 引入的,是对 NLJ 算法的优化。

NLJ 算法优化后的 BKA 算法的流程如下:

Batched Key Acess 流程

启用 BKA 算法:

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

前两个参数的作用是要启用 MRR。这么做的原因是,BKA 算法的优化要依赖于MRR。

BNL 算法的优化

优化的常见做法是,给被驱动表的 join 字段加上索引,把 BNL 算法转成 BKA 算法。

但是如果无法在被驱动表上加索引,那么:

考虑使用临时表,使用临时表的大致思路是:

1. 把表 t2 中满足条件的数据放在临时表 tmp_t 中;

2. 为了让 join 使用 BKA 算法,给临时表 tmp_t 的字段 b 加上索引;

3. 让表 t1 和 tmp_t 做 join 操作。

SQL语句为:

create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;

insert into temp_t select * from t2 where b>=1 and b<=2000;

select * from t1 join temp_t on (t1.b=temp_t.b);

总体来看,不论是在原表上加索引,还是用有索引的临时表,我们的思路都是让 join 语句

能够用上被驱动表上的索引,来触发 BKA 算法,提升查询性能。

上面如果不适用临时表进行优化,那么还有其他方式进行优化?

我们可以自己实现在业务端。实现流程大致如下:

1. select * from t1;取得表 t1 的全部 1000 行数据,在业务端存入一个 hash 结构,

比如 C++ 里的 set、PHP 的数组这样的数据结构。

2. select * from t2 where b>=1 and b<=2000; 获取表 t2 中满足条件的 2000 行

数据。

3. 把这 2000 行数据,一行一行地取到业务端,到 hash 结构的数据表中寻找匹配的数

据。满足匹配的条件的这行数据,就作为结果集的一行。

关于临时表的几个问题:

1.  binlog_format=row,那么跟临时表有关的语句,就不会记录到binlog 里。只在

binlog_format=statment/mixed 的时候,binlog 中才会记录临时表的操作。

2. 在使用临时表的时候,最后最好要写上 DROP TEMPORARY TABLE,删除临时表

3. 临时表只对本session会话可见,对其他的session不可见。

mysql单单写join_MySQL系列之Join大法相关推荐

  1. mysql update inner join_mysql update inner join错误

    update a set a.city=b.city FROM(SELECT * FROM zhujiagewang WHERE collecttime='2016-10-27′ AND city I ...

  2. mysql的full join_mysql实现full join

    展开全部 Oracle .DB2.SQL Server.PostgreSQL 支持 Full JOIN 但是 MySQL 是不支持的. 可以通过 LEFT JOIN  +   UNION  +  RI ...

  3. mysql入门很简单系列视频-学习笔记

    mysql入门很简单系列视频-学习笔记 视频链接:mysql入门很简单系列视频 https://www.bilibili.com/video/av14920200/ 以前主要就了解DDL.DML.DC ...

  4. 手写webpack系列一:了解认识loader-utils

    Created By JishuBao on 2019-03-29 12:38:22 Recently revised in 2019-04-01 12:38:22   欢迎大家来到技术宝的掘金世界, ...

  5. 自己动手写Docker系列 -- 5.7实现通过容器制作镜像

    简介 在上篇中我们实现了rm命令,删除存在的容器,本篇中,将完善之前的文件系统隔离,实现容器与容器之间的文件系统隔离 源码说明 同时放到了Gitee和Github上,都可进行获取 Gitee: htt ...

  6. MySQL怎么运行的系列(十)Innodb中的锁:记录锁、临键锁、间隙锁、意向锁

    本系列文章目录 展开/收起 MySQL怎么运行的系列(一)mysql体系结构和存储引擎 MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法 Mysql怎么运 ...

  7. MySQL怎么运行的系列(五)Innodb表空间(table space)、区(extent)和段(segment)

    本系列文章目录 展开/收起 MySQL怎么运行的系列(一)mysql体系结构和存储引擎 MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法 Mysql怎么运 ...

  8. MySQL怎么运行的系列(十一)快照读、锁定读、半一致性读 和 加锁语句分析

    本系列文章目录 展开/收起 MySQL怎么运行的系列(一)mysql体系结构和存储引擎 MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法 Mysql怎么运 ...

  9. MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法

    本系列文章目录 展开/收起 MySQL怎么运行的系列(一)mysql体系结构和存储引擎 MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法 MySQL怎么运 ...

最新文章

  1. ARM架构和ARM核区别和联系
  2. html5点击显示展开列表,HTML5 - 如何折叠和展开复杂的表格元素
  3. varchar 保存英文中文区别。
  4. 爬虫图片href是html图片,xpath爬虫实例,爬取图片网站百度盘地址和提取码
  5. 五个值得放收藏夹吃灰的Go CheatSheet 站点
  6. Java中类方法的快速入门
  7. hbase 核心知识
  8. 《JQuery 能干点啥~》第四讲 html() 与 text()的赋值比较
  9. build.gradle文件介绍
  10. linux实用技巧:ubuntu18.04安装samba服务器实现局域网文件共享
  11. 英语心理测试脸型软件,心理测试:脸型分析自己
  12. alert#40;1#41; to xss.haozi.me with #0x02
  13. Git还能这样玩?居然被他玩出了新花样
  14. 一种简单的PCB加温电路设计
  15. 分享一些程序员必备网站
  16. webstorm直接运行js
  17. 关于打印机能够搜到但是无法连接的解决办法
  18. 这些问题才是阻碍蓝牙耳机音质的元凶,2021什么牌子蓝牙耳机靠谱?
  19. 程序媛眼中的程序员,piupiu~
  20. hippo4j启动登录不上

热门文章

  1. java zip文件操作,java 关于 zip 文件 的 基本操作
  2. quill鼠标悬浮 出现提示_外设报道——DELUX多彩M618X垂直鼠标颠覆创新
  3. Android开发之git命令创建tag提交远程仓库的方法(图文教程)
  4. 关于 VC 执行顺序
  5. python统计提取数量_python中统计计数的几种方法和Counter的介绍
  6. Envoy Proxy构建控制平面指南
  7. V神:区块链跨链技术大规模应用将在一到两年内爆发
  8. tp5.0行为的用法,可以存入json数据,方便读取数据。
  9. opensuse x64下编译Ice源码(以编译c++为例)
  10. Medoo 开源项目发布,超轻量级的PHP SQL数据库框架