44 答疑(三)--join的写法/Simple nested loop join的性能问题/Distinct和group by的性能/备库自增主键问题
44 答疑(三)
Join的写法
35节介绍了join执行顺序,加了straight_join,两个问题:
--1 如果用left join,左边的表一定是驱动表吗
--2 如果两个表的join包含多个条件的等值匹配,是都要写到on里面呢,还是只把一个写到on,把其他的条件写到where部分?
create table a(f1 int, f2 int, index(f1))engine=innodb;
create table b(f1 int, f2 int)engine=innodb;
insert into a values(1,1),(2,2),(3,3),(4,4),(5,5),(6,6);
insert into b values(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
表a和b都有两个字段f1和f2,不同的是表a的字段上有f1的索引,两种写法
select * from a left join b on(a.f1=b.f1) and (a.f2=b.f2); /*Q1*/
select * from a left join b on(a.f1=b.f1) where (a.f2=b.f2);/*Q2*/

可以看到q1查询返回的数据集是6行,表a中没有满足匹配条件的记录,查询结果中也会返回,并把b的各个字段为null,语句q2返回4行,where是过滤条件,最后执行。

--驱动表是a,被驱动表是b
--由于表b的f1字段上没有索引,所以使用的是block nested loop(BNL)算法,具体执行流程
---1 把表a的内如读入join_buffer,这里select *,所有字段f1和f2放入了join_buffer
---2 顺序扫描表b,对于每一行数据,判断join条件(也就是a.f1=b.f1 and a.f2=b.f2)是否满足,满足条件的记录,作为结果集的一行返回,如果语句中有where条件,需要先判断where部分,满足条件后在返回
--3 表b扫描完成后,对于没有被匹配的表a的行,把剩余字段补上null,放入结果集中。

看q2的执行计划

这个语句以表b为驱动表,如果一个join语句的extra中扫描都没有写的话,表示使用的是index nested-loop join(NLJ)算法。Q2的执行流程
--顺序扫描表b,每一行用b.f1到a中去查,匹配到记录后判断a.f2=b.f2,满足条件的话就作为结果集的一部分返回。
在语句q2里面,where a.f2=b.f2表示,结果集不会包含b.f2=null的行,从语义上跟join一致,优化器改成了join,然后因为表a上f1有索引,就把b作为驱动表,a为被驱动表,使用nlj算法,使用show warnings可以看到优化器改写之后的语句,跟参数sql_mode有关。
在left join中,左边的表不一定是驱动表。
如果需要left join的语义,就不能把被驱动表的字段放在where条件里面做等值判断或者不等值判断,必须都写在on里面。
select * from a join b on(a.f1=b.f1) and (a.f2=b.f2); /*Q3*/
select * from a join b on(a.f1=b.f1) where (a.f2=b.f2);/*Q4*/

2个语句的执行计划是一样的。
Simple nested loop join的性能问题
35节中提到bnl算法和simple nested loop join算法都是需要判断M*N次(m,n分别是join的表的行数),但是在simple nested loop join算法的每轮判断都需要走全表扫描,因此性能上bnl算法执行起来会快很多。
BNL算法的执行逻辑:
--1首先,将驱动表的数据全部读入内存join_buffer中,这里join_buffer是无序数组
--2 然后,顺序遍历被驱动表的所有行,每一行数据都跟join_buffer中的数据进行匹配,匹配成功则作为结果集的一部分返回。
Simple nested loop join算法执行的逻辑是:顺序取出驱动表中的每一行数据,到被驱动表中做全表扫描匹配,匹配成功则作为结果集的一部分返回。
Simple nested loop join算法其实也是把数据读入内存里,然后按照条件进行判断,为什么性能差距胡这么大
--解释这个问题,需要用到mysql中索引结构和buffer pool的相关知识
--1 在对被驱动表做全表扫描的时候,如果数据没有在buffer pool中,就需要等待这部分数据从磁盘读入:从磁盘读取数据到内存,会影响正常业务的buffer pool命中率,
而且这个算法会对驱动表的数据做多次访问,更容易将这些数据页放到buffer pool的头部,
--2 即使被驱动表数据都在内存中,每次查找”下一个记录操作”,都是类似指针操作。而join_buffer中是数组,遍历的成本更低。
所以说,BNL算法的性能会更好些
Distinct和group by的性能
如果只需要去重,不需要执行聚合函数,distinct和group by那种效率更高?
select a from t group by a order by null;
select distinct a from t;
首先要说明,这种group by的写法,并不是sql标准写法,标准的group by语句是需要在select部分加一个聚合函数
select a,count(*) from t group by a order by null;
按照字段a分组,计算每组的a出现的次数,在这个结果里,由于做的是聚合计算,相同的a只出现一次。没有了count(*)之后,就不再需要执行”计算总数”的逻辑第一条语句就变成,
按照字段a做分组,相同的a的值只返回一行,而这就是distinct的语义,所以不需要执行聚合函数时,distinct和group by这两条语句的语义和执行流程是相同,因此性能也相同。
--1 创建一个临时表,临时表有一个字段a,并且这个字段a上创建一个唯一索引
--2 遍历表t,依次取出数据插入临时表中:
---如果发现唯一键冲突,就跳过
---否则插入成功
--3 遍历完成后,将临时表作为结果集返回给客户端。
备库自增主键问题
create table t(id int auto_increment primary key);
insert into t values(null);
在binlog_format=statement时,语句a先获取id=1,然后语句b获取id=2,b提交,写binlog,然后a在提交写binlog,如果在备库重放,是不是会发生语句b获取的id为1,语句a获取的id为2的情况?
通过解析binlog文件发现,在insert语句之前,有set insert_id=1,这条命令的意思,这个线程下一次需要用到自增值的时候,不论当前表的自增值是多少,固定用1这个值,所以如果b语句先提交,在binlog就是这样
SET INSERT_ID=2;
语句 B;
SET INSERT_ID=1;
语句 A;
所以,在备库执行的时候,自增主键的值是不会不一致的。
44 答疑(三)--join的写法/Simple nested loop join的性能问题/Distinct和group by的性能/备库自增主键问题的更多相关文章
- 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- 1122MySQL性能优化之 Nested Loop Join和Block Nested-Loop Join(BNL)
转自http://blog.itpub.net/22664653/viewspace-1692317/ 一 介绍 相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说 ...
- Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join
关系数据库技术的精髓就是通过关系表进行规范化的数据存储,并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理. 表的三种关联方式: nested loop:从A表抽一条记录,遍历B表查找匹配 ...
- Merge join、Hash join、Nested loop join对比分析
简介 我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge Join,Hash Join ...
- join中级篇---------hash join & merge join & nested loop Join
嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: ...
- 三大表连接方式详解之Nested loop join和 Sort merge join
在早期版本,Oracle提供的是nested-loop join,两表连接就相当于二重循环,假定两表分别有m行和n行 如果内循环是全表扫描,时间复杂度就是O(m*n) 如果内循 ...
- 禁用nested loop join里的spool
禁用nested loop join里的spool 转载自: https://blogs.msdn.microsoft.com/psssql/2015/12/15/spool-operator-and ...
- SQL Server nested loop join 效率试验
从很多网页上都看到,SQL Server有三种Join的算法, nested loop join, merge join, hash join. 其中最常用的就是nested loop join. 在 ...
- oracle多表连接方式Hash Join Nested Loop Join Merge Join
在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式: 嵌套循环(Nested Loops (NL) ...
随机推荐
- 线性渐变css
从上到下的线性渐变: #grad { background: -webkit-linear-gradient(red, blue); /* Safari 5.1 - 6.0 */ background ...
- 算法学习之二分查找算法的python实现
——参考自<算法图解> 我们假设需要查找的数组是有序的(从大到小或者从小到大),如果无序,可以在第四行后插入一句 my_list.sort() 完整代码如下 def binary_sear ...
- LOAD - 装载或重载一个共享库文件
SYNOPSIS LOAD 'filename' DESCRIPTION 描述 这个命令装载一个共享库文件到PostgreSQL服务器的地址空间. 一旦一个文件被装载,如果该文件前面曾经装载过,那么服 ...
- PAT Advanced 1007 Maximum Subsequence Sum (25 分)
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to ...
- python3-使用__slots__
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.先定义class: class Student(object): pa ...
- java ThreadGroup源码分析
使用: import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction; public class Test { public s ...
- Python 基本数据类型详解
1.数字 int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647在64位系统上,整数的位数为64位,取值范围为-2* ...
- 【NOIP2016提高A组8.11】种树
题目 分析 题目要求把图删点,删成树. 考虑一下树的定义,点数n=边数m+1 并且,树中点两两之间联通,那么选的点就不能是割点. 可以用tarjan将图中最大的联通块,保证其中点两两之间有不止一条路径 ...
- ajax请求成功,但是进入error
ajax请求成功,这是因为json数据没有严格按json格式返回
- 【leetcode】827. Making A Large Island
题目如下: 解题思路:这个题目可以进行拆分成几个子问题.第一,求出island的数量,其实就是 200. Number of Islands,这个很简单,DFS或者BFS都能搞定:第二,除了求出isl ...