35 | 别再说不能使用Join了(这次是优化Join查询-下篇)

云里雾里,不知所以~

一、前言

现有两张表:t1(1000行数据,a=1001-id)的值,t2(100w行数据)

语句如下:

create table t1(id int primary key, a int, b int, index(a));
create table t2 like t1;
drop procedure idata;
delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=1000)do
    insert into t1 values(i, 1001-i, i);
    set i=i+1;
  end while;
  
  set i=1;
  while(i<=1000000)do
    insert into t2 values(i, i, i);
    set i=i+1;
  end while;
end;;
delimiter ;
call idata();

二、正文

1.Multi-Range Read 优化原理是什么?优化起到的作用是什么?优化的场景是什么?

  • 1)通过根据非主键索引,定位到满足条件的记录,将 id 值放入 read_rnd_buffer 中 ;2)将read_rnd_buffer根据id进行递增排序;3)排序后的 id 数组,依次到主键 id 索引中查记录,并作为结果返回。

  • 因为大多数的数据都是按照主键递增顺序插入得到的,所以我们可以认为,如果按照主键的递增顺序查询的话,对磁盘的读比较接近顺序读,能够提升读性能。

  • 范围查找,单条查找意义不大。

2.Batched Key Access(BKA)算法原理是什么?步骤原理是什么?原理图是什么?BKA算法如何启用?

  • 主要是对NLJ算法的优化,利用MRR的特性。

  • 1)针对NLJ中驱动表的多行数据加载到join buffer中【不确定是否正确:第一次是从表1中取数据到join_buffer中,然后再joi_buffer中排序后去往表二中取字段a,然后在read_rnd_buffer中排序再入找到id号取数据。两次读表都是顺序读】。2)根据被驱动表关联字段,查找与被驱动表索引值匹配的主键索引id。3)合并记录

  • set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';--需要依赖MRR所以设置开启参数

3.BNL算法转BKA算法时如果创建索引会浪费资源,但是不创建索引的话这个语句的等值条件要判断 10 亿次,那么,有没有两全其美的办法呢?没有比临时表方案方案更好的策略?

  • 1)把表 t2 中满足条件的数据放在临时表 tmp_t 中;2)为了让 join 使用 BKA 算法,给临时表 tmp_t 的字段 b 加上索引;3)让表 t1 和 tmp_t 做 join 操作。

  • hash-join,但是MySQL不支持,所以需要业务测做一个select * from t1操作,把结果存到hash表中

三、思考题

现在有一个三个表 join 的需求,假设这三个表的表结构如下:
CREATE TABLE `t1` (
 `id` int(11) NOT NULL,
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL,
 `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

create table t2 like t1;
create table t3 like t2;
insert into ... //初始化三张表的数据

语句的需求实现如下的 join 逻辑:
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 上的索引,来支持这个 join 语句,你会加哪些索引呢?同时,如果我希望你用 straight_join 来重写这个语句,配合你创建的索引,你就需要安排连接顺序,你主要考虑的因素是什么呢?

答: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;
如果改写成 straight_join,要怎么指定连接顺序,以及怎么给三个表创建索引。
第一原则是要尽量使用 BKA 算法。需要注意的是,使用 BKA 算法的时候,并不是“先计算两个表 join 的结果,再跟第三个表 join”,而是直接嵌套查询的。
具体实现是:在 t1.c>=X、t2.c>=Y、t3.c>=Z 这三个条件里,选择一个经过过滤以后,数据最少的那个表,作为第一个驱动表。此时,可能会出现如下两种情况。
第一种情况,如果选出来是表 t1 或者 t3,那剩下的部分就固定了。
如果驱动表是 t1,则连接顺序是 t1->t2->t3,要在被驱动表字段创建上索引,也就是 t2.a 和 t3.b 上创建索引;
如果驱动表是 t3,则连接顺序是 t3->t2->t1,需要在 t2.b 和 t1.a 上创建索引。
同时,我们还需要在第一个驱动表的字段 c 上创建索引。
第二种情况是,如果选出来的第一个驱动表是表 t2 的话,则需要评估另外两个条件的过滤效果。
总之,整体的思路就是,尽量让每一次参与 join 的驱动表的数据集,越小越好,因为这样我们的驱动表就会越小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值