掌握MySQL链接查询到底什么是驱动表html
准备咱们须要的表结构和数据
两张表 studnet(学生)表和score(成绩)表, 建立表的SQL语句以下
mysql
CREATE TABLE student
(id
int(11) NOT NULL,no
varchar(20) DEFAULT NULL,name
varchar(20) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
算法
CREATE TABLE score
(id
int(11) NOT NULL,no
varchar(20) DEFAULT NULL,chinese
double(4,0) DEFAULT NULL,math
double(4,0) DEFAULT NULL,engilsh
double(4,0) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MySQL链接查询分为如下三种
left join 左链接,用法以下,这种查询会把左表(student)全部数据查询出来,右表不存在的用空表示,结果图以下
sql
select * from student s1 left join score s2 on s1.on = s2. onoop
right join 右链接, 用法以下,这种查询会把右表(score)全部数据查询出来,左表不存在的用空表示,结果图以下性能
select * from student s1 right join score s2 on s1.no = s2.no优化
inner join 内链接,用法以下,这种查询会把左右表都存在的数据查询出来,不存在数据忽略,结果图以下url
select * from student s1 inner join score s2 on s1.no = s2.no.net
链接查询中须要注意的点
什么是驱动表,什么是被驱动表,这两个概念在查询中有时容易让人搞混,有下面几种状况,你们须要了解。
code
当链接查询没有where条件时,左链接查询时,前面的表是驱动表,后面的表是被驱动表,右链接查询时相反,内链接查询时,哪张表的数据较少,哪张表就是驱动表
当链接查询有where条件时,带where条件的表是驱动表,不然是被驱动表
怎么肯定咱们上面的两种状况呢,执行计划是不会骗人的,咱们针对上面状况分别看看执行计划给出的答案
首先第一种状况,student表中3条数据,score表中2条数据,但两张表中只有一条数据是关联的(编号是1),看以下SQL查询
//左链接查询
explain select * from student s1 left join score s2 on s1.no = s2.no
//右链接查询
explain select * from student s1 right join score s2 on s1.no = s2.no
//内链接查询
explain select * from student s1 inner join score s2 on s1.no = s2.no
执行计划中靠前的表是驱动表,咱们看下面三种图中,是否是全度符合状况一,第一张图中s1是驱动表,第二张图中s2是驱动表,第三种途中s2是驱动表
其次第二种状况,仍是上面三种SQL语句,咱们分别加上where条件,再来看看执行计划的结果是什么样呢?
//左链接查询
explain select * from student s1 left join score s2 on s1.no = s2.no
where s2. no = 1
//右链接查询
explain select * from student s1 right join score s2 on s1.no = s2.no
where s1.no = 1
//内链接查询
explain select * from student s1 inner join score s2 on s1.no = s2.no
where s1.no = 1
咱们看下面三种执行计划结果,全都以where条件为准了,并且跟上面状况一的都相反了,所以状况二也是获得了验证.
链接查询优化
要理解链接查询优化,得先理解链接查询的算法,链接查询经常使用的一共有两种算法,咱们简要说明一下
Simple Nested-Loop Join Algorithms (简单嵌套循环链接算法)
好比上面的查询中,咱们肯定了驱动表和被驱动表,那么查询过程以下,很简单,就是双重循环,从驱动表中循环获取每一行数据,再在被驱动表匹配知足条件的行。
for (row1 : 驱动表) {
for (row2 : 被驱动表){ if (conidtion == true){ send client } }
}
Index Nested-Loop Join Algorithms (索引嵌套循环链接算法)
上面双重for循环的查询中,相信不少研发人员看到这种状况第一个想法就是性能问题,是的,join查询的优化思路就是小表驱动大表,并且在大表上建立索引(也就是被动表建立索引),若是驱动表建立了索引,MySQL是不会使用的
for (row1 : 驱动表) {
索引在被驱动表中命中,不用再遍历被驱动表了
}
Block Nested-Loop Join Algorithm(基于块的链接嵌套循环算法)
其实很简单就是把一行变成了一批,块嵌套循环(BNL)嵌套算法使用对在外部循环中读取的行进行缓冲,以减小必须读取内部循环中的表的次数。例如,若是将10行读入缓冲区并将缓冲区传递到下一个内部循环,则能够将内部循环中读取的每一行与缓冲区中的全部10行进行比较。这将内部表必须读取的次数减小了一个数量级。
MySQL链接缓冲区大小经过这个参数控制 : join_buffer_size
MySQL链接缓冲区有一些特征,只有没法使用索引时才会使用链接缓冲区;联接中只有感兴趣的列存储在其联接缓冲区中,而不是整个行;为每一个能够缓冲的链接分配一个缓冲区,所以能够使用多个链接缓冲区来处理给定查询;在执行链接以前分配链接缓冲区,并在查询完成后释放链接缓冲区
因此查询时最好不要把 * 做为查询的字段,而是须要什么字段查询什么字段,这样缓冲区可以缓冲足够多的行。
从上面的执行计划中其实咱们已经看到了 useing join buffer了,是的,那是由于咱们对两张表都有建立索引
三种算法优先级
第一种算法忽略,MySQL不会采用这种的,当咱们对被驱动表建立了索引,那么MySQL必定使用的第二种算法,当咱们没有建立索引或者对驱动表建立了索引,那么MySQL必定使用第三种算法
MySQL链接算法官方文档
https://dev.mysql.com/doc/refman/8.0/en/nested-loop-joins.html