34 | 到底可不可以使用join?
34 | 到底可不可以使用join?
讲述:林晓斌
时长16:42大小15.25M
Index Nested-Loop Join
Simple Nested-Loop Join
Block Nested-Loop Join
小结
上期问题时间
赞 93
提建议
精选留言(175)
- 没时间了ngu置顶2019-01-30join这种用的多的,看完还是有很大收获的。像之前讲的锁之类,感觉好抽象,老是记不住,唉。
作者回复: 嗯嗯,因为其实每个同学的只是背景不一样。 这45讲里,每个同学都能从部分文章感觉到有收获,我觉得也很好了😆 不过 锁其实用得也多的。。 我以前负责业务库的时候,被开发同学问最多的问题之一就是,为啥死锁了^_^
共 8 条评论96 - 信信2019-01-30老师好,回答本期问题:如果驱动表分段,那么被驱动表就被多次读,而被驱动表又是大表,循环读取的间隔肯定得超1秒,这就会导致上篇文章提到的:“数据页在LRU_old的存在时间超过1秒,就会移到young区”。最终结果就是把大部分热点数据都淘汰了,导致“Buffer pool hit rate”命中率极低,其他请求需要读磁盘,因此系统响应变慢,大部分请求阻塞。
作者回复: 👍
共 19 条评论343 - 斜面镜子 Bill2019-01-31因为 join_buffer 不够大,需要对被驱动表做多次全表扫描,也就造成了“长事务”。除了老师上节课提到的导致undo log 不能被回收,导致回滚段空间膨胀问题,还会出现:1. 长期占用DML锁,引发DDL拿不到锁堵慢连接池; 2. SQL执行socket_timeout超时后业务接口重复发起,导致实例IO负载上升出现雪崩;3. 实例异常后,DBA kill SQL因繁杂的回滚执行时间过长,不能快速恢复可用;4. 如果业务采用select *作为结果集返回,极大可能出现网络拥堵,整体拖慢服务端的处理;5. 冷数据污染buffer pool,block nested-loop多次扫描,其中间隔很有可能超过1s,从而污染到lru 头部,影响整体的查询体验。展开
作者回复: 👍很赞 之前知识点的也都加进来啦
共 6 条评论209 - 老杨同志2019-01-30对被驱动表进行全表扫描,会把冷数据的page加入到buffer pool.,并且block nested-loop要扫描多次,两次扫描的时间可能会超过1秒,使lru的那个优化失效,把热点数据从buffer pool中淘汰掉,影响正常业务的查询效率
作者回复: 漂亮👍
60 - Zzz2019-01-30林老师,我没想清楚为什么会进入young区域。假设大表t大小是M页>old区域N页,由于Block Nested-Loop Join需要对t进行k次全表扫描。第一次扫描时,1~N页依次被放入old区域,访问N+1页时淘汰1页,放入N+1页,以此类推,第一次扫描结束后old区域存放的是M-N+1~M页。第二次扫描开始,访问1页,淘汰M-N+1页,放入1页。可以把M页想象成一个环,N页想象成在这个环上滑动的窗口,由于M>N,不管是哪次扫描,需要访问的页都不会在滑动窗口上,所以不会存在“被访问的时候数据页在 LRU 链表中存在的时间超过了 1 秒“而被放入young的情况。我能想到的会被放入young区域的情况是,在当次扫描中,由于一页上有多行数据,需要对该页访问多次,超过了1s,不管这种情况就和t大小没关系了,而是由于page size太大,而一行数据太少。展开
作者回复: 你说得对,分两类情况, 小于bp 3/8的情况会跑到young, 大于3/8的会影响young部分的更新
共 5 条评论40 - 清风浊酒2019-01-30老师您好,left join 和 right join 会固定驱动表吗?
作者回复: 不会强制,但是由于语义的关系,大概率上是按照语句上写的关系去驱动,效率是比较高的
共 2 条评论36 - 泡泡爱dota2019-01-31explain select * from t1 straight_join t2 on (t1.a=t2.a) where t1.a < 50; 老师, 这条sql为什么t1.a的索引没有用上, t1还是走全表
作者回复: 如果数据量不够多,并且满足a<50的行,占比比较高的话,优化器有可能会认为“还要回表,还不如直接扫主键id”
共 4 条评论36 - 郝攀刚จุ๊บ2019-01-30业务逻辑关系,一个SQL中left join7,8个表。这我该怎么优化。每次看到这些脑壳就大!
作者回复: 😓 Explain下,没用用index nested-loop 的全要优化
共 7 条评论25 - 萤火虫2019-01-30年底了有一种想跳槽的冲动 身在武汉的我想出去看看 可一想到自身的能力和学历 又不敢去了 苦恼...
作者回复: 今年这情况还是要先克制一下^_^ 先把内功练起来😆
共 4 条评论24 - amazon10112019-01-30这个专栏受益匪浅,老师再搞个内核源码专栏:)共 2 条评论15
- 抽离の❤️2019-01-30早上听老师一节课感觉获益匪浅
作者回复: 好早呀🤝
14 - 张旭2020-09-28NLJ:驱动表选出一行行数据到被驱动表中查找 BNL:把驱动表的数据分段读入join buffer中,然后和被驱动表join MRR:针对回表操作做的优化,把索引上的主键排序,然后再回表,这样就可以随机读变为顺序读 BKA:是针对NLJ的优化,不是像NLJ一行行取出数据去被驱动表查找,而是一次取出一批到join buffer中然后到被驱动表中查找,获得关联的记录,再使用MRR优化获取最终结果展开14
- 思考特~2019-03-03老师,这边想请教一个困扰很久的问题,用mysql经常会制定这么一个规则,不允许多表join。从实际情况看,几乎不太可能遵守这个规则,有个交易的业务场景涉及 用户表 300W、订单表 900W、支付表 900W,每次需要查一个用户下面的订单信息可能就有点慢了,但是还能接受,如果是查询一个团体的订单信息,这个量就非常可观了,查询有时候根本返回不了结果。根本无法避免多表Join,所以想问问老师,在这种需要多表Join业务场景下,如何设计表,来提升性能?或者有这方面推荐的资料可以参考的展开
作者回复: 我的建议就是用好NLJ和BKA算法😆
共 5 条评论12 - 呵呵2019-02-11老师,新年好! 优化器会自动选择小表作为驱动表,那么我们人为把小表写成驱动表还有意义吗?
作者回复: 新年好 嗯优化器大部分时候会选对,如果选不对,我们就得自己强行指定了哈 其实了解这个原理主要还是指导我们根据最优的join顺序,来创建被驱动表字段上的索引
13 - 柚子2019-01-30join在热点表操作中,join查询是一次给两张表同时加锁吧,会不会增大锁冲突的几率? 业务中肯定要使用被驱动表的索引,通常我们是先在驱动表查出结果集,然后再通过in被驱动表索引字段,分两步查询,这样是否比直接join委托点?
作者回复: join也是普通查询,都不需要加锁哦,参考下MVCC那篇; 就是我们文中说的,“分两步查询,先查驱动表,然后查多个in”,如果可以用上被驱动表的索引,我觉得可以用上Index Nested-Loop Join算法,其实效果是跟拆开写类似的
共 4 条评论11 - 啊啊啊哦哦2019-03-31NLJ join算法下。 驱动表假设全表先扫描。 这个全表扫描的数据存放在哪。 buffer bool中还是。全表扫描到单独的read buffer中? 我的理解是。 驱动表全表扫描的数据。是从buffer bool中找驱动表的数据到 read buffer中。如果buffer bool 没有。那么从磁盘。到buffer bool 然后在到read buffer 中。 我的理解对吗。
作者回复: 不是的 如果是NLJ,就是遍历过程中直接到被驱动表去匹配,匹配满足条件的行,就直接作为结果集发出去了,不需要临时内存
10 - 4032019-02-09用那个作为驱动表,mysql会自己优化么?
作者回复: 会的
10 - 10242019-02-19文中解释NLJ和BNL时间复杂度相同,都是M*N。但是对于BNL性能好于NLJ的原因只是提到:"BNL的判断是在内存中操作,速度上会快很多,性能也更好"。请问老师?这句话的言外之意是: NLJ的判断不是在内存中操作吗?不将数据加载到内存,CPU如何进行判断呢?
作者回复: 这个我在答疑文章中展开哈,其实还是“内存数据是从哪里来的”的问题。 我们这里说的是BNL比Simple nested loop 快哈
共 4 条评论8 - Ryoma2019-01-31上文中使用索引时扫描行数为200,但是根据字段a去做树搜索时,由于字段a是普通索引,在找到匹配值后还会继续匹配,实际上每个循环都做了至少两次的行扫描。 老师,这么理解对么?
作者回复: 是的,不过在MySQL 里面,这样算“扫描一行”,实际上确实做了两次树搜索
10 - felix2019-01-31不让用join,那用什么呢,用逗号分隔两表? join有多个条件的话,写在on后面和where后面有什么区别吗?
作者回复: 逗号分隔两表还是join 😄 下一篇会讲到优化,主要思路就是用上被驱动表索引哈
9