联接算法是MySql数据库用于处理联接的物理策略。在MySql 5.5版本仅支持Nested-Loops Join算法,如果联接表上有索引时,Nested-Loops Join是非常高效的算法。如果有索引时间复杂度为O(N),若没有索引,则可视为最坏的情况,时间复杂度为O(N²)。MySql根据不同的使用场景,支持两种Nested-Loops Join算法,一种是Simple Nested-Loops Join算法,另外一种是Block Nested-Loops Join算法。

Simple Nested-Loops Join算法

从一张表中每次读取一条记录,然后将记录与嵌套表中的记录进行比较。算法如下:

For each row r in R do

For each row s in S do

If r and s satisfy the join condition

Then output the tuple

假设在两张表R和S上进行联接的列都不含有索引,算法的扫描次数为:R+RxS,扫描成本为O(RxS)。

假设t1,t2和t3三张表执行INNER JOIN查询,并且每张表使用的联接类型如下:

Table Join Type

t1 range

t2 ref

t3 ALL

如果使用了Simple Nested-Loops Join算法,则算法实现的伪代码如下:

for each row in t1 matching range {

for each row in t2 matching reference key {

for each row in t3 {

if row satisfies join conditions,

send to client

}

}

}

但是当内部表对所联接的列含有索引时,Simple Nested-Loops Join算法可以利用索引的特性来进行快速匹配,此时的算法调整为如下:

For each row r in R do

lookup r in S index

If find s == r

Then output the tuple

对于联接的列含有索引的情况,外部表的每条记录不再需要扫描整张内部表,只需要扫描内部表上的索引即可得到联接的判断结果。

在INNER JOIN中,两张联接表的顺序是可以变换的,根据前面描述的Simple Nested-Loops Join算法,优化器在一般情况下总是选择将联接列含有索引的表作为内表。如果两张表R和S在联接列上都有索引,并且索引的高度相同,那么优化器会选择记录数少的表作为外部表,这是因为内部表的扫描次数总是索引的高度,与记录的数量无关。

下面这条SQL语句:

SELECT * FROM driver join user on driver.driver_id = user.uid;

其执行计划如下:

可以看到SQL先查询user表,然后将表driver上的索引和表user上的列uid进行匹配。

这里为什么首先使用user表,因为user表的联接列uid并没有索引,而driver表的联接列driver_id有索引,所以Simple Nested-Loops Join算法将driver表作为内部表。

注意:最终优化器确定联接表的顺序只会按照确切的扫描成本来确定,即:M(外表)+M(外表)*N(内表);这里的外表和内表分别指的是外表和内表的扫描次数,如果含有索引,就是索引B+树的高度,其他一般都是表的记录数。

Block Nested-Loops Join算法

如果联接表没有索引时,Simple Nested-Loops Join算法扫描内部表很多次,执行效率会非常差。而Block Nested-Loops Join算法就是针对没有索引的联接情况设计的,其使用Join Buffer(联接缓存)来减少内部循环取表的次数。

MySql数据库使用Join Buffer的原则如下:

系统变量Join_buffer_size决定了Join Buffer的大小。

Join Buffer可被用于联接是ALL、index、和range的类型。

每次联接使用一个Join Buffer,因此多表的联接可以使用多个Join Buffer。

Join Buffer在联接发生之前进行分配,在SQL语句执行完后进行释放。

Join Buffer只存储要进行查询操作的相关列数据,而不是整行的记录。

对于上面提到的三个表进行联接操作,如果使用Join Buffer,则算法的伪代码如下:

for each row in t1 matching range {

for each row in t2 matching reference key {

store used columns from t1, t2 in join buffer

if buffer is full {

for each row in t3 {

for each t1, t2 combination in join buffer {

if row satisfies join conditions,

send to client

}

}

empty buffer

}

}

}

if buffer is not empty {

for each row in t3 {

for each t1, t2 combination in join buffer {

if row satisfies join conditions,

send to client

}

}

}

举一个例子,把driver表的_create_date列和user表的create_date列的索引删除,进行联接查询,执行下面的SQL语句:

select _create_date FROM driver join user on driver._create_date = user.create_time;

再次查看SQL执行计划如下:

可以看到,SQL执行计划的Extra列中提示Using join buffer,这就代表使用了Block Nested-Loops Join算法。MySql 5.6会在Extra列显示更为详细的信息,如下面所示:

注意点:在MySql 5.5版本中,Join Buffer只能在INNER JOIN中使用,在OUTER JOIN中则不能使用,即Block Nested-Loops Join算法不支持OUTER JOIN。下面的left join语句:

select _create_date FROM driver left join user on driver._create_date = user.create_time;

在MySql 5.5中的执行计划如下:

可以看到并没有Using join buffer提示,这就意味着没有使用Block Nested-Loops Join算法,但是在MySql 5.6以后开始支持,上面的SQL语句在MySql 5.6中的执行计划如下:

对于上面的SQL语句,使用Block Nested-Loops Join算法需要的时间3.84秒,而不使用的时间是11.93秒。可以看出Block Nested-Loops Join算法对性能提示很多。

Batched Key Access Joins算法

MySql 5.6开始支持Batched Key Access Joins算法(简称BKA),该算法的思想是结合索引和group前面两种方法来提高(search for match)查询比较的操作,以此加快执行效率。

MySQL 5.6.3 implements a method of joining tables called the Batched Key Access (BKA) join algorithm. BKA can be applied when there is an index access to the table produced by the second join operand. Like the BNL join algorithm, the BKA join algorithm employs a join buffer to accumulate the interesting columns of the rows produced by the first operand of the join operation. Then the BKA algorithm builds keys to access the table to be joined for all rows in the buffer and submits these keys in a batch to the database engine for index lookups. The keys are submitted to the engine through the Multi-Range Read (MRR) interface. After submission of the keys, the MRR engine functions perform lookups in the index in an optimal way, fetching the rows of the joined table found by these keys, and starts feeding the BKA join algorithm with matching rows. Each matching row is coupled with a reference to a row in the join buffer.

Batched Key Access Join算法的工作步骤如下:

将外部表中相关的列放入Join Buffer中。

批量的将Key(索引键值)发送到Multi-Range Read(MRR)接口。

Multi-Range Read(MRR)通过收到的Key,根据其对应的ROWID进行排序,然后再进行数据的读取操作。

返回结果集给客户端。

Batched Key Access Join算法的本质上来说还是Simple Nested-Loops Join算法,其发生的条件为内部表上有索引,并且该索引为非主键,并且联接需要访问内部表主键上的索引。这时Batched Key Access Join算法会调用Multi-Range Read(MRR)接口,批量的进行索引键的匹配和主键索引上获取数据的操作,以此来提高联接的执行效率。

对于Multi-Range Read(MRR)的介绍属于MySql索引的内容,这里简单说明:MySQL 5.6的新特性MRR。这个特性根据rowid顺序地,批量地读取记录,从而提升数据库的整体性能。在MySQL中默认关闭的,如果需要开启:

mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

Query OK, 0 rows affected (0.00 sec)

总结

MySql 5.6以后越来越多的算法和策略的支持,让联接查询的操作效率越来越快,在学习的时候了解了这些优化效果,更重要的是在实践中明白SQL优化器的工作原理,善于用EXPLAIN等SQL分析命令,对MySql查询有更好的了解。

参考

有不对的地方希望大家多交流,谢谢。

《MySql技术内幕:SQL编程》

mysql数据库算法_MySql联接算法相关推荐

  1. Mysql数据库索引原理及算法原理

    前言 面试的时候总会被提及一些关于数据库操作的问题,那么数据库索引作为一项热门问题,总会被问到.最近在网上看到了一篇关于mysql数据库索引的好文章,认真看完之后肯定受益匪浅,(虽说有的地方我不太理解 ...

  2. mysql的联接算法_联接算法

    在Microsoft SQLServer Management Studio中执行查询时,如果选定工具栏中的 按钮,可以看到为查询生成的执行计划.执行计划以图形方式显示了SQL Server查询优化器 ...

  3. mysql数据库语言_mysql数据库sql语句基础知识

    1.数据库操作 查看当前数据库 SELECT DATABASE(); 显示用户名,数据库版本 SELECT user(), version(); 创建库 CREATE DATABASE[ IF NOT ...

  4. java中mysql数据库原理_MySql数据库索引原理

    本文主要是阐述索引机制,主要是说明存储引擎Innodb 第一部分主要从及理论层面讨论MySQL索引的数理基础. 第二部分结合MySQL数据库中InnoDB数据存储引擎中索引的实现讨论聚集索引.非聚集索 ...

  5. mysql数据库视图_MySQL数据库应用总结(九)—MySQL数据库视图的操作

    SQL语法预览: 创建视图:[create [or replace] [algorithm={undefined | merge | temptable}] view 视图名称(属性列) as sel ...

  6. mysql数据库导出_MySQL数据库导入导出详解[转发]

    1. 概述 MySQL数据库的导入,有两种方法: 1) 先导出数据库SQL脚本,再导入: 2) 直接拷贝数据库目录和文件. 在不同操作系统或MySQL版本情况下,直接拷贝文件的方法可能会有不兼容的情况 ...

  7. mysql 数据库编程_MySQL数据库编程(C++语言)

    MySQL数据库编程(C++语言) 发布时间:2018-05-24 21:06, 浏览次数:452 , 标签: MySQL 本文主要介绍使用C++语言连接和操作 MySQL 数据库的方法. 1. 准备 ...

  8. mysql数据库事务_MySQL数据库的事务管理

    小伙伴们不好意思,这两天有事没有及时的更新哈~希望小伙伴们见谅,那么开始我们今天的分享. MySQL 数据库的事务 我们之前分享数据库的数据操作,无外乎对数据库的数据进行增.删.改.查.就比如我们去买 ...

  9. mysql数据库安全审计_MySQL数据库安全日志审计工具

    说明 由于MySQL社区版没有自带的审计功能或插件,对于等级保护当中对数据库管理的要求的就存在一定的不满足情况的,抛开条条框框不说数据库的日志是值得研究的,通过收集数据库的日志到企业SOC平台便于安全 ...

最新文章

  1. HDU 3549 Flow Problem(最大流模版EK算法)
  2. 简历这样写,技术人都不直男了!
  3. android6.0升级名单,三星Android 6.0升级详细名单[多图]
  4. 【云栖大会】基因计算:解读生命的力量
  5. CMU Facebook论文解读 | 非局部神经网络(附代码实现)
  6. (学习笔记)Oracle表空间相关基本命令
  7. 学习 尚硅谷-宋红康 Java基本语法(上): 变量与运算符
  8. 浏览器的NPAPI插件技术不要学了,已经淘汰几年了
  9. 三级分销系统源码如何上传?
  10. 嵌入式Ubuntu 搭建caffee环境
  11. 刚从阿里、头条面试回来,java程序员社招自我介绍
  12. 安卓应用加固壳判断java厂商_使用frida来hook加固的Android应用的java层
  13. linux查看进程limits解释,linux中/etc/security/limits.conf配置文件说明
  14. vue-router路由history模式+nginx部署项目到非根目录下(实践版)
  15. 个人笔记,深入理解 JVM,很全!
  16. IEC101单点遥信非连续报文解析
  17. 解决本地计算机上的MySQL80服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
  18. 安装linux双系统简书,win10 + ubuntu18.04 双系统的安装
  19. love2d之路(一)环境配置
  20. UVM phase机制(一)

热门文章

  1. linux中tmp文件在哪,Linux系统中/tmp文件夹
  2. 腾讯T3手把手教你!从底层开始带你了解并发编程,重要概念一网打尽!
  3. 从标注好的xml文件中截取坐标点(人脸框四个点坐标)人脸图像并保存在指定文件夹
  4. 上海镇保城保四金比例
  5. 学Web的第二十一天
  6. 不规则动词分类记忆一览表
  7. An Efficient Joint Training Framework for Robust Small-Footprint Keyword Spotting(2020)
  8. 机器学习——回归中的相关度与R平方值及其应用
  9. 智慧社区解决方案上线!给社区装上智能大脑
  10. Nexus Repository和Docker Registry镜像仓库搭建及使用