34 | 到底可不可以使用join?

1.  join 有什么问题

2.  两个大小不同表 join,哪个做驱动表?

主键索引 id 和索引 a,b 上无索引。 t2 插1000 行, t1  100 行

一、Index Nested-Loop Join(NLJ)

select * from t1  straight_join t2 on (t1.a=t2.a);

straight_join 指定方式join:t1 驱动表,t2 被驱动表。

直接用 join 优化器选驱动表,影响分析执行过程。

图 1 使用索引字段 join 的 explain 结果  

1.  t1 读一行数据 R;       //全表扫描,扫描 100 行

2.  R 中a 字段到t2 里查    //树搜索,每次只扫一行,总100 行

3.  t2 满足条件行+R = 结果集一部分(一行);

4.  重复直到 t1 循环结束。

图 2 Index Nested-Loop Join 算法的执行流程  

1.1 能不能使用 join?

不使用 join,单表查询。不如直接 join 

1. select * from t1,所有数据,100 行1句

2.从每一行 R 取出字段 a 的值 $R.a;select * from t2 where a=$R.a;100 行100

3.返回结果+R = 结果集一行。//多100 次交互: 拼接 SQL 语句和结果

1.2 怎么选择驱动表?

驱动表(行数 N):全表扫描,被驱动表(行数M):树搜索。

树搜索复杂度: 2 为底M对数,log2M,查一行是 2*log2M

驱动表:N 行到被驱动表上匹配一次。

近似复杂度N + N*2*log2M。

N 对扫描行数影响更大,小表做驱动表。

二、Simple Nested-Loop Join

select * from t1  straight_join t2 on (t1.a=t2.b);

b 上没有索引, t2 全表扫描(100次)。总共扫描 100*1000=10 万行。

t1 和 t2 都是 10 万行表,要扫描 100 亿行,太“笨重”,MySQL 没用这个算法

三、Block Nested-Loop Join 没可用索引

1.   t1读入线程内存 join_buffer 中,select *整个 t1 放内存;

2.  扫描 t2,每行取出,跟 join_buffer 对比,满足 join 条件作为结果集一部分返回。

内存操作,速度快多,性能好。时间复杂度和上面一样

图 3 Block Nested-Loop Join 算法的执行流程  
图 4 不使用索引字段 join 的 explain 结果

3.1哪个表做驱动表

都一样

1.  总扫描行 M+N;(1100)

2.  判断次数是 M*N。(100*1000=10 万次join_buffer 无序数组)

3.2 t1 大表,join_buffer 放不下怎么办?

分段放(Block由来)。join_buffer_size 默认 256k,改成 1200,再执行:

1.  扫描表 t1,顺序读取数据行放入 join_buffer 中,放完第 88 行 join_buffer 满

2. 扫描表 t2,把 t2 中的每一行取出来,跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回;

3. 清空 join_buffer;重复上面

图 5 Block Nested-Loop Join -- 两段  

判断等值条件的次数还是不变的,依然是(88+12)*1000=10 万次。

3.3 驱动表选择问题

小表当驱动表。驱动表 N行,分 K段完成,被驱动表M行。

K = λ*N,λ (0,1),N 越大 K 越大

1.  扫描行数N+λ*N*M;

2.  内存判断 N*M 次。

考虑扫描行数,N 小结果小。λ才是关键因素,越小越好。

N 固定,什么参数会影响 K 的大小呢?(就是λ的大小)join_buffer_size。 分段越少,扫描次数越少。

join 语句很慢,把join_buffer_size 改大

四、能不能使用 join 语句?

1.   Index Nested-Loop Join 算法,没问题;

2.  Block Nested-Loop Join 算法不要,扫描行多。尤其大表上 join 操作,扫描被驱动表很多次,会占用大量的系统资源。

explain 结果,Extra 有没有出现“Block Nested Loop”字样。

五、用 join,选大表还是小表做驱动表?

1.  Index Nested-Loop Join ,小表

2.  Block Nested-Loop Join 算法:

join_buffer_size 足够一样不够小表

六、什么叫作小表

select * from t1  straight_join t2 on (t1.b=t2.b) where t2.id<=50;

select * from t2  straight_join t1 on (t1.b=t2.b) where t2.id<=50;

都用不上索引,第二:join_buffer 只放t2 前 50 行是“小表”),更好

另一组例子:

select t1.b,t2.*  from  t1  straight_join t2 on (t1.b=t2.b) where  t2.id<=100;

select t1.b,t2.*  from  t2  straight_join t1 on (t1.b=t2.b) where  t2.id<=100;

t1 放到 join_buffer 中,只放b值(小表) t1 为驱动表。

 t2 放 id、a 和 b。

两个表按照各自条件过滤,计算参与 join 各个字段总数据量,数据量小就是小表,驱动表。

小结

能否用被驱动表索引,对 join 性能影响大

用被驱动表索引join 好;否则,不要用;

用 join 时,小表做驱动表

思考题

Block Nested-Loop Join 算法,可能会因为 join_buffer 不够大,被驱动表做多次全表扫描。

被驱动表大表(冷数据),除查询可能会IO 压力大,MySQL 服务还有什么更严重影响?(结合上一篇知识点)

两种情况:

(1)数据量小于old,驱动表分段,被驱动表多次读,大表,循环读取间隔超1秒,移到young区Buffer pool hit rate命中率极低,其他请求读磁盘响应慢,阻塞。

(2 )被驱动表数据量大于 Buffer Pool ,影响young部分更新

评论1

为什么会进入young区域?

大表t M页>old区域N页,对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太大,而一行数据太少。

评论2

 join_buffer 不够大,多次全表扫描,“长事务”。除了导致undo log 不能被回收回滚段空间膨胀问题,还会出现:

1. 长期占DML锁,引发DDL拿不到锁堵满连接池

 2. SQL执行socket_timeout超时后业务接口重复发起IO负载上升雪崩;

3. 实例异常,DBA kill SQL因繁杂的回滚执行时间过长,不能快速恢复

4.select *返回,网络拥堵,拖慢服务端

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容