35 | join语句怎么优化?(问题未完待续)

NLJ 效果不错,BNL 大表 join 性能差,消耗 CPU 资源。都可继续优化

 t1 1000 行, a=1001-id 的值。a逆序。 t2 插入了 100 万行数据。

一、Multi-Range Read 优化

Read 优化 (MRR),顺序读盘。

第 4 篇文章“回表”普通索引 a 上查到主键 id ,根据主键 id 去查整行数据的过程。

select * from t1  where a>=1 and a<=100;

主键索引 B+ 树,每次只能根据一个主键 id 查一行一行行搜主键索引

图 1 基本回表流程

a 递增,id 变随机,随机访问,性能。虽按行查不能改,调整顺序加速

MRR思路:主键递增,磁盘读接近顺序读,提升读性能。

1.  索引 a,定位满足条件记录,id 值放read_rnd_buffer 中;

2.  read_rnd_buffer 中 id 进行递增排序

3.   id 记录返回

read_rnd_buffer_size 控制大小。read_rnd_buffer放满,清空继续循环。

稳定用 MRR 优化设置setoptimizer_switch="mrr_cost_based=off"。(优化器策略,判断消耗时,倾向不使用 MRR,就是固定用 MRR )

图 2 MRR 执行流程  
图 3 MRR 执行流程的 explain 结果

 Extra 多 Using MRR。read_rnd_buffer 按id 排序,结果集中行顺序相反

提升性能核心顺序性”:a 上查 id。排序,id查数据,

二、Batched Key Access

NLJ 的优化(放内存)

图 4 Index Nested-Loop Join 流程图

表 t2 每次都匹配一个值。MRR 用不上。

t1 多拿行一起传,先放临时内存join_buffer暂存驱动表数据

图 5 Batched Key Access 流程

放入 P1~P100,只会取查询需要字段。如放不下所有,分多段

启用先设置set optimizer_switch = 'mrr=on,mrr_cost_based=off,batched_key_access=on';  启用 MRRBKA 依赖于 MRR。

三、BNL 算法性能问题

被驱动表做多次扫描。大冷数据表,除导致 IO 压力大外,还有什么影响?

LRU 优化, old 区域。对 Buffer Pool 的命中率影响就不大。

冷表很大,出现另外一种情况:业务正常访问数据页,没有机会进入 young 区域(没有被合理淘汰)。

两种情况都影响 Buffer Pool 正常运作。

大表 join 操作虽然对 IO 有影响,语句执行结束后,对 IO 的影响结束。Buffer Pool 影响持续性,后续的查询慢慢恢复内存命中率。

增大join_buffer_size 的值,减少被驱动表扫描次数。BNL 影响:

1.  占用磁盘 IO 资源;

2.  判断 join 条件需M*N 次对比(M、N 分别是两张表的行数),占用 CPU 资源;

3.  Buffer Pool 热数据淘汰,影响内存命中率。

优化:被驱动表 join 字段索引,BNL 转BKA 算法。

四、BNL BKA

被驱动表索引直接转BKA不适合在被驱动表上建索引如:

select * from t1  join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000

t2 插 100 万,where后只有 2000 。同时低频的 SQL ,建索引就浪费。

1.  t1 所有字段取出来,存入 join_buffer 。1000行 完全存入 join_buffer_size(默认 256k)

2.  扫描t2,跟 join_buffer 对比不满足 t1.b=t2.b跳过[1,2000] 返回,否则跳过。

对于表 t2 每行,判断 join 是否满足的时候,遍历 join_buffer 所有行。判断等值条件的次数是 1000*100 万 =10 亿次,工作量大。

图 6 explain 结果
图 7 语句执行时间

Extra 显示用 BNL 算法。执行 1 分 11 秒。

 b 上创建索引浪费资源,不创建判断 10 亿次,浪费。两全其美办法:临时表:

1.  t2 满足条件数据放临时表 tmp_t 中;

2.  让 join 用 BKA 算法,给临时表 tmp_t 字段 b 加索引

3.  t1 和 tmp_t 做 join 操作。

create temporary  table temp_t(id int primary key, a int, b int, index(b))engine=innodb;

insert into  temp_t select * from t2 where b>=1 and b<=2000;//100 万

select * from t1  join temp_t on (t1.b=temp_t.b); //1000次索引查询

图 8 使用临时表的执行效果

原表上加索引,还是索引临时表,join 用被驱动表上索引,触发 BKA 算法,提升性能。

五、扩展-hash join

上面计算 10 亿次点儿傻。如 join_buffer 不是无序数组,是哈希表话,不是 10 亿判断,而是 100 万次 hash 查找。快多了(比临时表快

MySQL 优化器和执行器诟病:不支持哈希 join。优化思路自己实现:

1. select * from t1; t1 全部 1000 行数据,存 hash 结构,如 C++ 里的 set、PHP 的数组

2.  select * from t2 where b>=1 and b<=2000; t2 中满足条件2000 行

3.  2000 行数据,一行行取到业务端hash 结构数据表中寻找匹配数据作为结果集

小结

Index Nested-Loop Join(NLJ)和 Block Nested-Loop Join(BNL)的优化方法。

1.  BKA 优化是 MySQL 已经内置支持,默认用;

2.  BNL 效率低,建议你都尽量转成 BKA 算法。给被驱动表关联字段加上索引

3.  临时表改进方案,提前过滤出小数据 join ,效果好;

4.  MySQL 不支持 hash join,自己模拟,好于临时表

思考题

三个表 join 需求:

改写成straight_join,怎么指定连接顺序,怎么给三个表创建索引

第一原则: BKA 算法,直接嵌套查询。不是“先计算两个表 join 结果,再跟第三个join”,

实现:t1.c>=X、t2.c>=Y、t3.c>=Z 三个条件,数据最少第一驱动表

第一种情况

选出表 t1 或者 t3,剩下部分就固定。

1. 驱动表t1,连接顺序t1->t2->t3被驱动表t2.a 和 t3.b )字段建索引, 

2.  驱动表t3,连接顺序t3->t2->t1t2.b 和 t1.a 上创建索引。

驱动表 c 创建索引。

第二种情况

第一个驱动表t2,评估另外两个条件过滤效果。

评论1

select * from t1 join t2 on(t1.a=t2.a) 

join t3 on (t2.b=t3.b) 

where t1.c>=X and t2.c>=Y and t3.c>=Z;

快速定位t1、t2和t3的c字段建索引。join优先选择数量比较少两张表,t1.a=t2.a的行数小于满足t2.b=t3.b的行数,t1和t2join,行数少驱动表,被驱动表a上建立索引,结果放入join_buffer与t3进行join,被驱动表的t3的b上建索引。t1.c>=X ,t2.c>=Y ,t3.c>=Z

为什么不用一个索引,要分别建3个?

评论2

我还有个问题,开篇sql select * from t1 where a>=1 and a<=100;

a是索引列,有order by a,不使用MRR 优化,查询出来就是按a排序的,使用了mrr优化,是不是要额外排序?

答:用order by就不用MRR

ps: 固态硬盘顺序写随机写快

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

推荐阅读更多精彩内容