35 | join语句怎么优化?
该思维导图由 AI 生成,仅供参考
Multi-Range Read 优化
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了如何优化join语句,主要包括Multi-Range Read(MRR)优化和Batched Key Access(BKA)算法。MRR优化旨在通过范围查询和排序,提升性能,而BKA算法则是对Index Nested-Loop Join(NLJ)算法的优化,通过将驱动表的数据暂存到join_buffer,一次性传递多个值给被驱动表,以提高效率。文章详细解释了这两种优化方法的原理和执行流程,并指出了使用这些优化方法的注意事项。此外,还介绍了BNL算法对系统的影响以及BNL转BKA的优化方法。最后,还提到了哈希join的优化思路。总的来说,本文为读者提供了关于join语句优化的核心思想和具体实现方式,对优化数据库查询性能提供了有益的参考。文章还提出了一个思考题,让读者思考如何设计表t1、t2、t3上的索引来支持一个三个表join的需求,并用straight_join来重写这个语句,配合创建的索引。这为读者提供了一个实际问题来应用所学的知识。
《MySQL 实战 45 讲》,新⼈⾸单¥68
全部留言(118)
- 最新
- 精选
- 老杨同志我准备给 t1增加索引c t2增加组合索引b,c t3增加组合索引b,c select * from t1 straight_join t2 on(t1.a=t2.a) straight_join t3 on (t2.b=t3.b) where t1.c>=X and t2.c>=Y and t3.c>=Z; 另外我还有个问题,开篇提到的这句sql select * from t1 where a>=1 and a<=100; a是索引列,如果这句索引有order by a,不使用MRR 优化,查询出来就是按a排序的,使用了mrr优化,是不是要额外排序
作者回复: 对,好问题,用了order by就不用MRR了
2019-02-01561 - Mr.Strive.Z.H.L老师您好,新年快乐~~ 关于三表join有一个疑惑点需要确认: 老师您在评论中说到,三表join不会是前两个表join后得到结果集,再和第三张表join。 针对这句话,我的理解是: 假设我们不考虑BKA,就按照一行行数据来判断的话,流程应该如下(我会将server端和innodb端分的很清楚): 表是t1 ,t2 ,t3。 t1 straight_join t2 straight_join t3,这样的join顺序。 1. 调用innodb接口,从t1中取一行数据,数据返回到server端。 2. 调用innodb接口,从t2中取满足条件的数据,数据返回到server端。 3. 调用innodb接口,从t3中取满足条件的数据,数据返回到server端。 上面三步之后,驱动表 t1的一条数据就处理完了,接下来重复上述过程。 (如果采用BKA进行优化,可以理解为不是一行行数据的提取,而是一个范围内数据的提取)。 按照我上面的描述,确实没有前两表先join得结果集,然后再join第三张表的过程。 不知道我上面的描述的流程对不对?(我个人觉得,将innodb的处理和server端的处理分隔清晰,对于sql语句的理解,会透彻很多)
作者回复: 新年快乐,分析得很好。 可以再补充一句,会更好理解你说的这个过程 : 如果采用BKA进行优化,每多一个join,就多一个join_buffer
2019-02-0251 - 天王join语句的优化,NLJ算法的优化,MRR优化器会在join_buffer进行主键的排序,然后去主键索引树上一个个的查找,因为按照主键顺序去主键索引树上查找,性能会比较高,MRR优化接近顺序读,性能会比较高。BKA算法是对NLJ算法的优化,一次取出一批数据的字段到join_buffer中,然后批量join,性能会比较好。BKA算法依赖于MRR,因为批量join找到被驱动表的非聚集索引字段通过MRR去查找行数据
作者回复: 👍
2019-02-13333 - 郭健老师,有几个问题还需要请教一下: 1.上一章t1表100条数据,t21000条数据,mysql会每次都会准确的找出哪张表是合理的驱动表吗?还是需要人为的添加straight_join。 2.像left join这种,左边一定是驱动表吧?以左边为标准查看右边有符合的条件,拼成一条数据,看到你给其他同学的评论说可能不是,这有些疑惑。 3.在做join的时候,有些条件是可以放在on中也可以放在where中,比如(t1.yn=1 和t2.yn=1)这种简单判断是否删除的。最主要的是,需要根据两个条件才能join的(productCode和custCode),需要两个都在on里,还是一个在on中,一个在where中更好呢?
作者回复: 1. 正常是会自己找到合理的,但是用前explain是好习惯哈 2. 这个问题的展开我放到答疑文章中哈 3. 这也是好问题,需要分析是使用哪种算法,也放到答疑文章展开哈。 新年快乐~
2019-02-07231 - asdf100最近遇到这个需求,in里面的值个数有5万左右,出现的情况很少但存在,这种情况怎么处理。?手动创建临时表再join? 另外in内的值用不用手动排序?
作者回复: 不需要手动排序 不过5万个值太凶残了,语句太长不太好 这种就是手动创建内存临时表,建上hash索引,填入数据,然后join
2019-02-01825 - HuaMax前提假设:t1.c>=X可以让t1成为小表。同时打开BKA和MRR。 1、t1表加(c,a)索引。理由:A、t1.c>=X可以使用索引;B、加上a的联合索引,join buffer里放入的是索引(c,a)而不是去主键表取整行,用于与表t2的t1.a = t2.a的join查询,不过返回SELECT * 最终还是需要回表。 2、t2表加(a,b,c)索引。理由:A、加上a避免与t1表join查询的BNL;B、理由同【1-B】;C、加上c不用回表判断t2.c>=Y的筛选条件 3、t3表加(b,c)索引。理由:A、避免与t2表join查询的BNL;C、理由同【2-C】 问题: 1、【1-B】和【2-B】由于select *要返回所有列数据,不敢肯定join buffer里是回表的整行数据还是索引(c,a)的数据,需要老师解答一下;不过值得警惕的是,返回的数据列对sql的执行策略有非常大的影响。 2、在有join查询时,被驱动表是先做join连接查询,还是先筛选数据再从筛选后的临时表做join连接?这将影响上述的理由【2-C】和【3-C】 使用straight_join强制指定驱动表,我会改写成这样:select * from t2 STRAIGHT_JOIN t1 on(t1.a=t2.a) STRAIGHT_JOIN t3 on (t2.b=t3.b) where t1.c>=X and t2.c>=Y and t3.c>=Z; 考虑因素包括: 1、驱动表使用过滤条件筛选后的数据量,使其成为小表,上面的改写也是基于t2是小表 2、因为t2是跟t1,t3都有关联查询的,这样的话我猜测对t1,t3的查询是不是可以并行执行,而如果使用t1,t3作为主表的话,是否会先跟t2生成中间表,是个串行的过程? 3、需要给t1加(a,c)索引,给t2加(c,a,b)索引。
作者回复: 👍 很深入的思考哈 1. select * ,所以放整行;你说得对,select * 不是好习惯; 2. 第一次join后就筛选;第二次join再筛选; 新春快乐~
2019-02-02219 - WL请教老师两个问题: 1. 通过主键索引找到的数据会会不会先在内存中查询, 如果没有再去磁盘查询? 2. 为什么在通过主键索引查询数据时, 符合条件的数据以单条数据的方式读到内存中而不是以一整个数据页的方式读到内存中?
作者回复: 1. 通过普通索引也会,InnoDB的访问模式都是先内存,不在内存中,才到磁盘找; 2. 是以数据页的方式读到内存的,然后在从内存的这个数据页(默认16k)里面找到数据。
2019-02-11216 - 涛哥哥老师,对于现在的固态硬盘,这样类似顺序读写的数据库优化,不就不起作用了啊?
作者回复: 固态硬盘的顺序写还是比随机写快的
2019-03-2013 - TKbookBNL 算法效率低,建议你都尽量转成 BKA 算法。优化的方向就是给驱动表的关联字段加上索引; 老师最后总结的时候,这句话后面那句,应该是给被驱动表的关联字段加上索引吧。
作者回复: 对的,👍细致 已经发起勘误,谢谢你哦,新年快乐
2019-02-0111 - dzkk老师,记得我之前看mysql的join是和版本有关系的,另外NLJ是一个统称,被分为了SNLJ(Simple Nested-Loop Join,5.5版本之前采用的,当被驱动表上没有索引的时候使用,该方法比较粗暴,所以后来通过BNLJ进行了优化)、INLJ(Index Nested-Loop Join,被驱动表上有索引)、BNLJ(Block Nested-Loop Join,被驱动表上没有索引),另外了解到mariadb是支持了hash join的Block Nested Loop Hash (BNLH) join,没有使用过,不知道效果怎么样。不知道我了解的信息对不对。
作者回复: 你了解得比较全面哈 不过我怕在文章中写这么多概念,会看得晕。 实际上现在 Simple Nested-Loop Join 已经不会用了(太慢),有使用的就是 Index Nested-Loop Join 和 BKA优化哈。 MariaDB在优化器上做了很多工作,之前的文章本来也想介绍,后来发现得先把官方版本的说明白,然后我们可以在评论区扩展讨论。 BNLH 在MariaDB 5.3就引入了,流程跟我们“扩展-hash join”这段类似,对于等值join的效果还是很好的。
2019-02-0111