MySQL优化器特性(三)表关联之BKA(Batched Key Access)优化

俊达2年前技术文章1060

单表range查询时,可以使用MRR优化,先对rowid进行排序,然后再回表查询数据。在表关联的时候,也可以使用类似的优化方法,先根据关联条件取出被关联表的rowid,将rowid缓存在join buffer中,对rowid进行排序后,再回表获取数据。

一个例子

执行计划

出于测试的目的,给查询加上BKA hint(或MRR hint),执行计划Extra中显示“Using join buffer (Batched Key Access)”,说明表关联时,使用了BKA优化。

SQL
mysql> explain select /*+ BKA(t2) */ * from tb t1, tb t2 
    where t1.a = t2.a  and t1.c=2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ref
possible_keys: idx_c,idx_ab
          key: idx_c
      key_len: 5
          ref: const
         rows: 32
     filtered: 100.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ref
possible_keys: idx_ab
          key: idx_ab
      key_len: 5
          ref: test.t1.a
         rows: 32
     filtered: 100.00
        Extra: Using join buffer (Batched Key Access)
2 rows in set, 1 warning (0.00 sec)

表结构

上述测试使用的表结构和数据:

SQL
mysql> show create table tb\G
*************************** 1. row ***************************
       Table: tb
Create Table: CREATE TABLE `tb` (
  `a` int DEFAULT NULL,
  `b` int DEFAULT NULL,
  `c` int DEFAULT NULL,
  `id` int NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `idx_c` (`c`),
  KEY `idx_ab` (`a`,`b`)
) ENGINE=InnoDB AUTO_INCREMENT=321 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

mysql> select a,b,c , count(*) from tb group by a,b,c;
+------+------+------+----------+
| a    | b    | c    | count(*) |
+------+------+------+----------+
|    1 |    1 |    1 |       32 |
|    2 |    2 |    2 |       32 |
|    3 |    3 |    3 |       32 |
|    4 |    4 |    4 |       32 |
|    5 |    5 |    5 |       32 |
|    6 |    6 |    6 |       32 |
|    7 |    7 |    7 |       32 |
|    8 |    8 |    8 |       32 |
|    9 |    9 |    9 |       32 |
|   10 |   10 |   10 |       32 |
+------+------+------+----------+
10 rows in set (0.00 sec)

使用场景

和单表MRR优化类似,表关联时使用BKA优化有一些前提条件:

1、被驱动表的关联字段存在二级索引。如果使用被驱动表的关联条件是主键,则不会采用BKA优化。

2、需要回表访问被关联表。如果在查询中,被驱动表访问的字段都在索引中,不需要回表,则不会采用BKA优化。

3、使用BKA的执行计划成本比默认的Nest loop关联低,或者查询中添加了BKA或MRR hint。

BKA Join执行过程

bka.png

使用BKA算法关联,会用到Join Buffer。BKA关联执行过程大致如下:

第一阶段:往join buffer中写入驱动表的数据

1、获取驱动表的数据。将获取到的数据缓存到Join Buffer中。

2、评估驱动表的一条记录,需要占用多少内存。包括记录本身的长度,加上存放对应的被驱动表rowid需要的空间。

3、如果join buffer空间够,则继续往join buffer中加入驱动表记录。否则,分配MRR buffer,进入下一阶段。


第二阶段:填充MRR buffer

根据缓存的驱动表的记录,扫描被驱动表的索引,将得到的rowid缓存到MRR buffer中。

填充完成后对MRR buffer按rowid进行排序。


第三阶段:获取被驱动表的记录

1、根据rowid回表获取数据。

2、读取驱动表缓存在join buffer中的数据。

3、关联数据,并将关联后的数据返回给客户端。

如果数据还没有处理完成,重复以上几个阶段。

总结

BKA Join在实际中可能并不常见。不过通过学习BKA Join的实现方式,可以了解MySQL如何使用join buffer,也能帮我们更好地理解表关联在代码层面是如何实现的。

(本文的描述,以及SQL和执行计划基于mysql 8.0.31版本)

阅读剩余的48%

相关文章

MySQL运维实战之备份和恢复(8.5)xtrabackup恢复增量备份

恢复增量备份时,需要先对基础全量备份进行恢复,然后再依次按增量备份的时间进行恢复。这个例子中,相关备份文件的目录结构如下:/data/backup ├── full │ &nb...

MySQL运维实战(5.1) 字符和编码的基本概念

MySQL运维实战(5.1) 字符和编码的基本概念

字符和编码字符字符是符号,是人们用于交流的各类符号,如26个英文字母、汉字、标点符号、数学运算符、其他语言的字母和符号。编码编码是计算机中以二进制方式存储字符的方式。字符集字符集是字符和编码的映射表。...

MySQL运维实战(5.4) MySQL元数据乱码

表结构Comment乱码如果DDL实际编码和character_set_client设置不一致,也会引起乱码。$ cat test_comment_utf8.sql create...

MySQL运维实战(7.1) 开启GTID复制

MySQL从5.6版本开始支持GTID复制。开启GTID之后,主库上执行的每一个事务都有一个全局唯一的ID。GTID由两部分组成:server_uuid和事务序列号。初始化数据库时,会生成一个全局唯一...

MySQL运维实战之备份和恢复(8.9)xtrabackup备份指定表

备份部分表如果实例设置了参数innodb_file_per_table,xtrabackup可以备份部分表。通过--tables,--tables-file,--databases,--databas...

MySQL优化器特性(二)MRR优化

MySQL优化器特性(二)MRR优化

Index Range Scan索引范围扫描的一般步骤:1、根据where条件,从B+树定位到第一条记录。2、从索引页子节点中获取到行号(rowid),根据rowid回表查询数据。3、使用额外的whe...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。