0419MySQL 中 Join 的基本实现原理
转自http://www.kuqin.com/database/20081206/29717.html 简朝阳
JOIN的用法你真的知道吗?
在 MySQL 中,只有一种 Join 算法,就是大名鼎鼎的 Nested Loop Join,他没有其他很多数据库所提供的 Hash Join,也没有 Sort Merge Join。顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复。
还是通过示例和图解来说明吧,后面将通过我个人数据库测试环境中的一个 example(自行设计,非MySQL 自己提供) 数据库中的三个表的 Join 查询来进行示例。
注意:由于这里有些内容需要在MySQL 5.1.18之后的版本中才会体现出来,所以本测试的MySQL 版本为5.1.26
表结构:
*************************** 1. row ***************************
Table: user_group
Create Table: CREATE TABLE `user_group` (
`user_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
`user_type` int(11) NOT NULL,
`gmt_create` datetime NOT NULL,
`gmt_modified` datetime NOT NULL,
`status` varchar(16) NOT NULL,
KEY `idx_user_group_uid` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
insert into `user_group`(`user_id`,`group_id`,`user_type`,`gmt_create`,`gmt_modified`,`status`) values (1001,10001,1,'2017-04-19 00:00:00','2017-04-19 00:00:00','1'),(1002,10001,2,'2017-04-19 00:00:00','2017-04-19 00:00:00','2'),(1003,10001,2,'2017-04-19 00:00:00','2017-04-19 00:00:00','1'),(1004,10002,1,'2017-04-19 00:00:00','2017-04-19 00:00:00','3'),(1005,10002,1,'2017-04-19 00:00:00','2017-04-19 00:00:00','2'),(1006,10001,1,'2017-04-19 00:00:00','2017-04-19 00:00:00','2'),(1007,10003,2,'2017-04-19 00:00:00','2017-04-19 00:00:00','1');
sky@localhost : example 11:10:32> show create table group_messageG
*************************** 1. row ***************************
Table: group_message
Create Table: CREATE TABLE `group_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`gmt_create` datetime NOT NULL,
`gmt_modified` datetime NOT NULL,
`group_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`author` varchar(32) NOT NULL,
`subject` varchar(128) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_group_message_author_subject` (`author`,`subject`(16)),
KEY `idx_group_message_author` (`author`),
KEY `idx_group_message_gid_uid` (`group_id`,`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=97 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
insert into `group_message`(`id`,`gmt_create`,`gmt_modified`,`group_id`,`user_id`,`author`,`subject`) values (1,'2017-04-19 00:00:00','2017-04-19 00:00:00',10001,1001,'dd','dd'),(2,'2017-04-19 00:00:00','2017-04-19 00:00:00',10002,1002,'sss','sss'),(3,'2017-04-19 00:00:00','2017-04-19 00:00:00',10003,1003,'eeee','eee');
sky@localhost : example 11:10:43> show create table group_message_contentG
*************************** 1. row ***************************
Table: group_message_content
Create Table: CREATE TABLE `group_message_content` (
`group_msg_id` int(11) NOT NULL,
`content` text NOT NULL,
KEY `group_message_content_msg_id` (`group_msg_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
insert into `group_message_content`(`group_msg_id`,`content`) values (1,'fdafdafdafds'),(2,'fafdasddddddddddddddddddddddddddddddddddddddddddd');
使用Query如下:
from user_group g,group_message m,group_message_content c
where g.user_id = 1
and m.group_id = g.group_id
and c.group_msg_id = m.id
看看我们的 Query 的执行计划:
-> from user_group g,group_message m,group_message_content c
-> where g.user_id = 1
-> and m.group_id = g.group_id
-> and c.group_msg_id = m.idG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: g
type: ref
possible_keys: user_group_gid_ind,user_group_uid_ind,user_group_gid_uid_ind
key: user_group_uid_ind
key_len: 4
ref: const
rows: 2
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: m
type: ref
possible_keys: PRIMARY,idx_group_message_gid_uid
key: idx_group_message_gid_uid
key_len: 4
ref: example.g.group_id
rows: 3
Extra:
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ref
possible_keys: idx_group_message_content_msg_id
key: idx_group_message_content_msg_id
key_len: 4
ref: example.m.id
rows: 2
Extra:
我们可以看出,MySQL Query Optimizer 选择了 user_group 作为驱动表,首先利用我们传入的条件 user_id 通过 该表上面的索引 user_group_uid_ind 来进行 const 条件的索引 ref 查找,然后以 user_group 表中过滤出来的结果集的 group_id 字段作为查询条件,对 group_message 循环查询,然后再通过 user_group 和 group_message 两个表的结果集中的 group_message 的 id 作为条件 与 group_message_content 的 group_msg_id 比较进行循环查询,才得到最终的结果。没啥特别的,后一个引用前一个的结果集作为条件,实现过程可以通过下图表示:

下面的我们调整一下 group_message_content 去掉上面的 idx_group_message_content_msg_id 这个索引,然后再看看会是什么效果:
Query OK, 96 rows affected (0.11 sec)
sky@localhost : example 10:21:06> explain
-> select m.subject msg_subject, c.content msg_content
-> from user_group g,group_message m,group_message_content c
-> where g.user_id = 1
-> and m.group_id = g.group_id
-> and c.group_msg_id = m.idG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: g
type: ref
possible_keys: idx_user_group_uid
key: idx_user_group_uid
key_len: 4
ref: const
rows: 2
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: m
type: ref
possible_keys: PRIMARY,idx_group_message_gid_uid
key: idx_group_message_gid_uid
key_len: 4
ref: example.g.group_id
rows: 3
Extra:
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 96
Extra: Using where; Using join buffer
我们看到不仅仅 group_message_content 表的访问从 ref 变成了 ALL,此外,在最后一行的 Extra信息从没有任何内容变成为 Using where; Using join buffer,也就是说,对于从 ref 变成 ALL 很容易理解,没有可以使用的索引的索引了嘛,当然得进行全表扫描了,Using where 也是因为变成全表扫描之后,我们需要取得的 content 字段只能通过对表中的数据进行 where 过滤才能取得,但是后面出现的 Using join buffer 是一个啥呢?
我们知道,MySQL 中有一个供我们设置的参数 join_buffer_size ,这里实际上就是使用到了通过该参数所设置的 Buffer 区域。那为啥之前的执行计划中没有用到呢?
实际上,Join Buffer 只有当我们的 Join 类型为 ALL(如示例中),index,rang 或者是 index_merge 的时候 才能够使用,所以,在我们去掉 group_message_content 表的 group_msg_id 字段的索引之前,由于 Join 是 ref 类型的,所以我们的执行计划中并没有看到有使用 Join Buffer。

当我们使用了 Join Buffer 之后,我们可以通过下面的这张图片来表示 Join 完成过程:
本文出自:http://www.jianzhaoyang.com/database/mysql_join_buffer_nested_loop_implement
0419MySQL 中 Join 的基本实现原理的更多相关文章
- 【原创】大数据基础之Spark(8)Spark中Join实现原理
spark中join有两种,一种是RDD的join,一种是sql中的join,分别来看: 1 RDD join org.apache.spark.rdd.PairRDDFunctions /** * ...
- 关于python多线程编程中join()和setDaemon()的一点儿探究
关于python多线程编程中join()和setDaemon()的用法,这两天我看网上的资料看得头晕脑涨也没看懂,干脆就做一个实验来看看吧. 首先是编写实验的基础代码,创建一个名为MyThread的 ...
- 学习重点:1、金典的设计模式在实际中应用2、JVM原理3、jui源代码
学习重点:1.金典的设计模式在实际中应用 2.JVM原理 3.jui源代码
- Linq中join & group join & left join 的用法
Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报 分类: C#(14) 文章 ...
- Oracle中join left,join right,inner join,(+) 等
Oracle中join left,join right,inner join,(+) 等 博客分类: Oracle 建表create table TEST1create table TEST1( ...
- org.apache.commons.lang.StringUtils 中 Join 函数
转自 http://my.oschina.net/zenglingfan/blog/134872 写代码的时候,经常会碰到需要把一个List中的每个元素,按逗号分隔转成字符串的需求,以前是自己写一段比 ...
- Spring中EmptyResultDataAccessException异常产生的原理及处理方法
Spring中EmptyResultDataAccessException异常产生的原理及处理方法 Spring中使用JdbcTemplate的queryForObject方法,当查不到数据时会抛出如 ...
- 基于接口回调详解JUC中Callable和FutureTask实现原理
Callable接口和FutureTask实现类,是JUC(Java Util Concurrent)包中很重要的两个技术实现,它们使获取多线程运行结果成为可能.它们底层的实现,就是基于接口回调技术. ...
- Spring框架中IoC(控制反转)的原理(转)
原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...
随机推荐
- luogu1169 棋盘制作
题目大意 有一个有m*n个格子的矩形,每个格子都有黑或白两种颜色.现要求将该矩形分别裁剪成一个小矩形或一个小正方形,使得这个矩形和正方形是个国际象棋棋盘,且面积最大. 题解 首先,为了简化问题,我们每 ...
- PCB MS SQL表值函数与CLR 表值函数 (例:字符串分割转表)
将字符串分割为表表经常用到,这里 SQL表值函数与CLR 表值函数,两种实现方法例出来如下: SELECT * FROM FP_EMSDB_PUB.dbo.SqlSplit('/','1oz/1.5 ...
- prim解决最小生成树问题
#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> ...
- 工具分享3:VMware 10虚拟机、MS-DOS 7.1、安装教程(MS-DOS环境安装)
VMware 10工具下载地址: 网页下载链接:http://www.xp510.com/xiazai/ossoft/desktools/22610.html MS-DOS .10镜像下载地址: 网页 ...
- python 线程池和锁
一.死锁现象与递归锁 锁:Lock线程安全,多线程操作时,内部会让所有线程排队处理.如:list/dict/Queue 线程不安全 + 人 => 排队处理. import thre ...
- 可变长度参数列表(Stering...aaa)
- “阻塞”与"非阻塞"与"同步"与“异步"
链接:http://www.zhihu.com/question/19732473/answer/20851256来源:知乎 “阻塞”与"非阻塞"与"同步"与“ ...
- css的选择器效率分析
我们都知道,CSS具有叠加性(同一个元素被多条样式规则指定),继承性(后代元素会继承前辈元素的一些样式和属性)和优先级 (由于CSS的叠加性和继承性,将产生优先级,这指的是哪条样式规则会最终作用于指定 ...
- Android java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader......couldn't find "libweibosdkcore.so
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/ ...
- Android之通过配置Flavor实现一个项目打包成多个apk
最近我老大问我一个问题,说Android可不可以像iOS那样,通过target对项目进行管理啊.老大提这个问题也是正常的,我公司的主要是帮别的公司做硬件定制的,每定制一个硬件就要定制一个APP,但是很 ...