MySQL Join 优化

MySQL Join的使用

一、使用join语句的优势?

  1. 使用join语句,性能比强行拆成多个单表执行SQL语句的性能要好;

  2. 使用join语句的话,需要让小表做驱动表

    前提是,“可使用被驱动表的索引”

二、怎么选择驱动表?

在join语句执行过程中,驱动表是走全表扫面,而被驱动表是走树搜索(需建立索引)

使用小表做驱动表;

三、什么是MRR?

Multi-Range-Read 优化(MRR),这个优化的主要目的是尽量使用顺序读盘

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

假设,执行此语句,MRR优化的设计思路,执行流程:

select * from t1 where a>=1 and a<=100;
  1. 根据索引 a,定位到满足条件的记录,将id值放入read_rnd_buffer中;

  2. 将read_rnd_buffer 中的id进行递增排序;

  3. 排序后的id数组,依次到主键id索引中查记录,并作为结果返回;

    read_rnd_buffer的大小是由read_rnd_buffer_size参数控制的,若步骤 1 read_rnd_buffer存满了,就会先执行完步骤2、3,然后情况read_rnd_buffer,之后继续招索引a的下个记录,并继续循环;

稳定使用MRR优化的话,需要设置set optimizer_switch=“mrr_cost_based=off”

文档说,是现在的优化器策略,判断消耗的时候,会更倾向于不使用MRR,把mrr_cose_based设置为off,就是固定使用MRR了

总结

MRR提升性能的核心:能够再索引 a 上做范围查询,得到足够多的主键,完成排序后再回表,体现出顺序性的优势。

四、优化:

1.NLJ优化:

从驱动表t1,一行行的取出 a 的值,再到被驱动表t2去join,此时没有利用到MRR的优势

如果可以使用Index Nested-Loop join 算法,应该选择小表做驱动表,可以用被驱动表上的索引,其实是没问题的;

img

2.BKA优化:

Batched Key Access,是MySQL 5.6引入的对Index Nested-Loop JoinNLJ)的优化。

img

  1. BKA优化的思路,复用了join_buffer

  2. 在BNL算法中,利用了join_buffer来暂存驱动表的数据,在NLJ里面并没有利用到join_buffer

  3. join_buffer中放入的数据为P1~P100,表示只会取查询所需要的字段

    如果join_buffer放不下P1~P100,就会将这100行数据分成多段执行

启用:

BKA算法依赖于MRR
SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

3.BNL优化:

  1. 可能会多次扫描被驱动表,占用磁盘IO资源
  2. 判断Join条件需要执行M∗NM∗N次对比,如果是大表会占用非常多的CPU资源
  3. 可能会导致Buffer Pool的热数据被淘汰正常的业务数据无法成为热数据,进而影响内存命中率

注意:如果优化器选择了BNL算法,就需要做优化:

  1. 给被驱动表Join字段加索引,把BNL算法转换成BKA算法;
  2. 临时表;

五、怎么优化join语句?

NLJ、BNL的优化方法:

  1. BKA算法是对NLJ算法的优化,一次取出一批数据的字段到join_buffer中,然后批量join;
  2. BKA算法依赖于MRR,因为批量join找到被驱动表的非聚集索引字段通过MRR去查找行数据;
  3. BKA优化是MySQL已经内置支持的,建议默认使用;
  4. BNL算法效率低,建议都尽量转成BKA算法,优化的方向就是给被驱动表的关联字段加上索引;

参考资料:

《MySQL 实战45讲》

发布了147 篇原创文章 · 获赞 170 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Fe_cow/article/details/103269837
今日推荐