MySQL Batched Key Access

 

Batched Key Access是MySQL 5.6 版本中的新特性,是一种用户提高表join性能的算法。
Batched Key Access
       对于多表join语句,当MySQL使用索引访问第二个join表的时候,使用一个join buffer来收集第一个操作对象生成的相关列值。BKA构建好key后,批量传给引擎层做索引查找。key是通过MRR接口提交给引擎的. 这样,MRR使得查询更有效率。
大致的过程如下:

  1. BKA使用join buffer保存由join的第一个操作产生的符合条件的数据。
  2. 然后BKA算法构建key来访问被连接的表,并批量使用MRR接口提交keys到数据库存储引擎去查找。
  3. 提交keys之后,MRR使用最佳的方式来获取行并反馈给BKA .

       BKA使用join buffer size来确定buffer的大小,buffer越大,访问被join的表/内部表就越顺序。
       MRR接口有2个应用场景:
       场景1:应用于传统的基于磁盘的存储引擎(innodb,myisam),对于这些引擎join buffer中keys是一次性提交到MRR,MRR通过key找到rowid,通过rowid来获取数据
       场景2:应用于远程存储引擎(NDB),来自join buffer上的部分key,从SQL NODE发送到DATA NODE,然后SQL NODE会收到通过相关关系匹配的行组合。然后使用这些行组合匹配出新行。然后在发送新key,直到发完为止。

 

  • BNL和BKA,MRR的关系

        BNL和BKA都是批量的提交一部分结果集给下一个被join的表(标记为T),从而减少访问表T的次数,那么它们有什么区别呢?BNL和BKA的思想是类似的,详情见:《nest-loop-join官方手册》
       第一 BNL比BKA出现的早,BKA直到5.6才出现,而BNL至少在5.1里面就存在。
       第二 BNL主要用于当被join的表上无索引,Join buffering can be used when the join is of type ALL or index (in other words, when no possible keys can be used, and a full
scan is done, of either the data or index rows, respectively)
       第三 BKA主要是指在被join表上有索引可以利用,那么就在行提交给被join的表之前,对这些行按照索引字段进行排序,因此减少了随机IO,排序这才是两者最大的区别,但是如果被join的表没用索引呢?那就使用BNL了。
      BKA实现的过程中就是通过传递keys给MRR接口,本质上还是在MRR里面实现,下面这幅图则展示了它们之间的关系:

 

  • 如何使用

       通过调整系统参数optimizer_switch的值,batched_key_access设置为on,因为BKA使用了MRR,因此也要打开MRR,但是基于成本优化MRR算法不是特别准确官方文档推荐关闭
mrr_cost_based,将其设置为off。

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on'

      另外多表join语句 ,被join的表/非驱动表必须索引可用。

转载于:https://www.cnblogs.com/vadim/p/7403847.html

### MySQL 中回表的概念 在 MySQL 数据库中,当查询涉及非聚簇索引时,可能会发生回表现象。具体来说,回表是指通过非聚簇索引查找记录时,先定位到该索引的叶子节点中的主键值或其他唯一标识符,然后再利用这些标识符去聚簇索引中检索完整的行数据[^3]。 对于不同类型的存储引擎: - **InnoDB** 使用的是聚集索引结构,即其聚簇索引就是按照主键顺序排列的数据本身;而非聚簇索引则只保存指向对应聚簇索引位置的信息(通常是主键)。因此,在 InnoDB 上执行基于次级索引的查询时,如果所需字段未被完全包含于次级索引之内,则会发生回表操作来获取剩余列的数据。 - **MyISAM** 并不存在真正意义上的聚簇索引,而是采用独立的 B+Tree 结构分别管理索引和实际数据文件。这意味着即使是在 MyISAM 表上的非主键索引扫描也不会引发严格定义下的“回表”,因为可以直接依据索引项所含有的文件偏移量快速定位目标数据行。 ### 回表的操作过程 假设有如下 SQL 查询语句用于从 `users` 表中选取名为 Alice 的用户的姓名和年龄属性: ```sql EXPLAIN SELECT name, age FROM users WHERE name = 'Alice'; -- 假设此查询可以仅依赖于 (name,age) 组成的联合索引来完成,无需额外访问其他地方取得更多资料 -> 不会触发回表动作 ``` 然而,当我们尝试取出整个用户对象的所有信息时, ```sql EXPLAIN SELECT * FROM users WHERE name = 'Alice'; -- 此处由于缺少必要的辅助索引支持,不得不借助主键回到原始表格里寻找其余缺失部分 -> 将会产生回表行为 ``` 上述情况表明,是否会出现回表取决于查询条件与现有索引之间的匹配程度。理想情况下,应当尽可能创建能够满足业务逻辑需求并有效防止不必要的回表发生的复合型或单一列索引[^4]。 为了降低因频繁回表带来的性能损耗,建议采取以下措施之一或者组合应用: - 构建覆盖索引,使得一次性的索引命中即可提供全部所需的输出结果; - 启用多版本并发控制机制下的批量读取功能(Multi-Version Concurrency Control with Batched Key Access),从而一次性加载多个相邻记录以减少单独发起 IO 请求的数量; - 频繁使用的查询路径应特别注意优化,比如避免通配符开头模糊匹配、过度宽泛的选择范围等问题,以此提高整体系统的响应速度和服务质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值