关于Mysql 的 ICP、MRR、BKA等特性

MySQL性能调优---BKA MySQL 5.6版本开始增加了提高表join性能的Batched Key Access (BKA)算法BKA是对于多表join语句,当MySQL使用索引访问第二个join表的时候,使用一个join buffer来收集第一个操作对象生成的相关列值。BKA构建好key后,批量传给引擎层做索引查找。key是通过MRR接口提交给引擎的,这样,MRR使得查询更有效率。 阅读详情

一、ICP( Index_Condition_Pushdown)

对 where 中过滤条件的处理,根据索引使用情况分成了三种:

如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索引过滤,把满足的行从表中读取出。ICP能减少Server层访问存储引擎的次数和引擎层访问基表的次数。

  • session级别设置:set optimizer_switch="index_condition_pushdown=on

  • 对于InnoDB表,ICP只适用于辅助索引

  • 当使用ICP优化时,执行计划的Extra列显示Using index condition提示

  • 不支持主建索引的ICP(对于Innodb的聚集索引,完整的记录已经被读取到Innodb Buffer,此时使用ICP并不能降低IO操作)

  • 当 SQL 使用覆盖索引时但只检索部分数据时,ICP 无法使用

  • ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例

index_condition_pushdown会大大减少行锁的个数,如select for update, 因为行锁是在引擎层的

 例如:

现在的索引

show index from sm_performance_all;
+--------------------+------------+-------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table              | Non_unique | Key_name                      | Seq_in_index | Column_name          | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------------+------------+-------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| sm_performance_all |          0 | PRIMARY                       |            1 | id                   | A         |       40527 |     NULL | NULL   |      | BTREE      |         |               |
| sm_performance_all |          1 | FK_a9t29a4b2af1vfny1j2minc1x  |            1 | company_id           | A         |         316 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_n3ng4a5qju19fw8qy4uskp4g1  |            1 | bill_id              | A         |       21532 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_eb13u3xwslt9t7wwuycg7vha6  |            1 | car_id               | A         |       16794 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_2bfhskvklf6mdk557tc3yy3y1  |            1 | commission_entity_id | A         |         177 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_6fr5ib5iyjyu155dncmc48cwr  |            1 | member_card_id       | A         |          34 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_93p22vcog266wa82i44a6m18b  |            1 | user_id              | A         |         483 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | FK_p6nc7l6ewnkcpm2y4o3wct81r  |            1 | member_card_bill_id  | A         |           4 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | billId_userId_memberCarBillId |            1 | bill_id              | A         |       24194 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | billId_userId_memberCarBillId |            2 | user_id              | A         |       25688 |     NULL | NULL   | YES  | BTREE      |         |               |
| sm_performance_all |          1 | billId_userId_memberCarBillId |            3 | member_card_bill_id  | A         |       25946 |     NULL | NULL   | YES  | BTREE      |         |               |
+--------------------+------------+-------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
11 rows in set (0.00 sec)

现在的语句执行情况

explain select * from sm_performance_all p where p.date_created>'2018-01-01'  and p.date_created< '2018-02-01' and p.type=0;
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
|  1 | SIMPLE      | p     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 40527 |     1.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

添加索引后

ALTER TABLE sm_performance_all add index date_created_type(date_created, type );

explain select * from sm_performance_all p where p.date_created>'2018-01-01'  and p.date_created< '2018-02-01' and p.type=0;
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys     | key               | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | p     | NULL       | range | date_created_type | date_created_type | 6       | NULL |    1 |    10.00 | Using index condition |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

二、MRR(Multi-Range Read )

随机 IO 转化为顺序 IO 以降低查询过程中 IO 开销的一种手段,这对IO-bound类型的SQL语句性能带来极大的提升。

MRR can be used for InnoDB and MyISAM tables for index range scans and equi-join operations.

  • A portion of the index tuples are accumulated in a buffer.

  • The tuples in the buffer are sorted by their data row ID.

  • Data rows are accessed according to the sorted index tuple sequence.

上述的SQL语句需要根据辅助索引date_created_type进行查询,但是由于要求得到的是表中所有的列,因此需要回表进行读取。而这里就可能伴随着大量的随机I/O。这个过程如下图所示:

而MRR的优化在于,并不是每次通过辅助索引就回表去取记录,而是将其rowid给缓存起来,然后对rowid进行排序后,再去访问记录,这样就能将随机I/O转化为顺序I/O,从而大幅地提升性能。这个过程如下所示:

然而,在MySQL当前版本中,基于成本的算法过于保守,导致大部分情况下优化器都不会选择MRR特性。为了确保优化器使用mrr特性,请执行下面的SQL语句:

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

读取全部字段时

explain select * from sm_performance_all p where p.date_created>'2018-01-01'  and p.date_created< '2018-02-01' and p.type=0;
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys     | key               | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | p     | NULL       | range | date_created_type | date_created_type | 6       | NULL |    1 |    10.00 | Using index condition; Using MRR |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)

只读取部分字段时

读取外键 explain select car_id from sm_performance_all p where p.date_created>'2018-01-01'  and p.date_created< '2018-02-01' and p.type=0;
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys     | key               | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | p     | NULL       | range | date_created_type | date_created_type | 6       | NULL |    1 |    10.00 | Using index condition; Using MRR |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)
读取主键
 explain select id from sm_performance_all p where p.date_created>'2018-01-01'  and p.date_created< '2018-02-01' and p.type=0;
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys     | key               | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | p     | NULL       | range | date_created_type | date_created_type | 6       | NULL |    1 |    10.00 | Using where; Using index |
+----+-------------+-------+------------+-------+-------------------+-------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

For MRR, a storage engine uses the value of the read_rnd_buffer_size system variable as a guideline for how much memory it can allocate for its buffer. 

默认256KB

show GLOBAL VARIABLES like '%buffer_size';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| bulk_insert_buffer_size | 8388608  |
| innodb_log_buffer_size  | 16777216 |
| innodb_sort_buffer_size | 1048576  |
| join_buffer_size        | 262144   |
| key_buffer_size         | 8388608  |
| myisam_sort_buffer_size | 8388608  |
| preload_buffer_size     | 32768    |
| read_buffer_size        | 131072   |
| read_rnd_buffer_size    | 262144   |
| sort_buffer_size        | 262144   |
+-------------------------+----------+
10 rows in set (0.00 sec)

三、表连接实现方式

3.1 Nested Loop Join

将驱动表/外部表的结果集作为循环基础数据,然后循环该结果集,每次获取一条数据作为下一个表的过滤条件查询数据,然后合并结果,获取结果集返回给客户端。Nested-Loop一次只将一行传入内层循环, 所以外层循环(的结果集)有多少行, 内存循环便要执行多少次,效率非常差。

EXPLAIN SELECT * from sm_performance_all  p LEFT JOIN sm_bill b ON p.bill_id > b.car_id where p.company_id>1024;
+----+-------------+-------+------------+-------+------------------------------+------------------------------+---------+------+--------+----------+------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys                | key                          | key_len | ref  | rows   | filtered | Extra                                          |
+----+-------------+-------+------------+-------+------------------------------+------------------------------+---------+------+--------+----------+------------------------------------------------+
|  1 | SIMPLE      | p     | NULL       | range | FK_a9t29a4b2af1vfny1j2minc1x | FK_a9t29a4b2af1vfny1j2minc1x | 9       | NULL |  20263 |   100.00 | Using index condition; Using MRR               |
|  1 | SIMPLE      | b     | NULL       | ALL   | car_id_idx                   | NULL                         | NULL    | NULL | 738383 |   100.00 | Range checked for each record (index map: 0x2) |
+----+-------------+-------+------------+-------+------------------------------+------------------------------+---------+------+--------+----------+------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

3.2 Block Nested-Loop Join

将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数。主要用于当被join的表上无索引。

CREATE TABLE t1 (a int PRIMARY KEY, b int);
CREATE TABLE t2 (a int PRIMARY KEY, b int);
INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10);
INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5);
EXPLAIN 
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | PRIMARY       | NULL | NULL    | NULL |    9 |    33.33 | Using where                                        |
|  1 | SIMPLE      | t2    | NULL       | ALL  | PRIMARY       | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

3.3 Batched Key Access

当被join的表能够使用索引时,就先好顺序,然后再去检索被join的表。对这些行按照索引字段进行排序,因此减少了随机IO。如果被Join的表上没有索引,则使用老版本的BNL策略。

mysql数据库BKA算法详解 BKA算法详解 Batched Key Access理解了 MRR 性能提升的原理,我们就能理解 MySQL 在 5.6 版本后开始引入的 BatchedKey Access(BKA) 算法了。这个 BKA 算法,其实就是对 NLJ 算法的优化。我们再来看看上一篇文章中用到的 NLJ 算法的流程图: 图 4 Index Nested-Loop Join 流程图NLJ 算法执行的逻辑是:从驱动表 t1,一行行地取出 a 的值,再到被驱动表 t2 去做join。也就是说,对于表 t2 来说,每. 阅读详情

相关推荐

CodeBlocks如何将英文环境改为中文

一、下载汉化包(链接如下) 链接:https://pan.baidu.com/s/166U9WGPbJXu2hyD7q9EiJQ 提取码:2333 二、选择路径 将汉化包中的文件(CodeBlocks.mo、zh_CN.mo、zh_CN.po)放到CodeBlocks安装路径下的​​​​​​CodeBlocks/share/CodeBlocks/locale/zh_CN文件夹中,路径中的文件夹没有就新建。 注:此处需严格按照要求来,切勿自定义文件夹名 三、内部调试 打开CodeBlocks,..

云隐雾匿的博客 2万+

一文读懂什么是MySQL索引下推(ICP

ICP(Index Condition Pushdown)是在MySQL 5.6版本上推出的查询优化策略,把本来由层做的索引条件检查下推给存储引擎层来做,以降低回表和访问存储引擎的次数,提高查询效率。为了理解ICP是如何工作的,我们先了解下没有使用ICP的情况下,MySQL是如何查询的:使用ICP的情况下,查询过程如下:先创建一张表,并插入记录 查看一下表记录 注意,这张表里创建了联合索引,假设我们想查询如下语句: 3.1 不使用索引下推 在不使用索引下推的情况下,根据联合索引“最左匹配”原则

Aiky哇 1722

基于Simulink的MIMO-OFDM系统仿真建模示例

MIMO概述MIMO技术利用多个天线进行信号发送和接收,通过空间复用来提高数据传输速率,或通过空间分集来增强信号的可靠性。OFDM概述OFDM是一种将高速率数据流分成多个低速数据流并行传输的技术,每个子载波都采用调制方式(如BPSK、QPSK),并通过IFFT/FFT变换实现串并转换。MIMO-OFDM优势结合了MIMO的空间分集增益与OFDM对抗多径效应的能力,适用于宽带无线通信系统。提供了更高的数据速率和更好的频谱效率,是现代无线通信标准(如4G LTE、5G NR等)的核心技术之一。

xiaoheshang_123的博客 312

MySQL索引下推(Index Condition Pushdown, ICP)优化深入解析

数据库性能优化是现代软件开发中不可或缺的一环。在MySQL中,索引的使用往往是提高查询性能的关键。自5.6版本起,MySQL引入了一个强大的优化器功能,名为索引下推(Index Condition Pushdown, 简称ICP)。通过ICP,我们可以显著提升部分查询的效率,尤其是在使用索引过滤数据时。本文将详细介绍ICP的原理、作用以及应用场景。

一名后端程序猿 4091

mysql 索引 icp

7.1版本索引区别 icp(Index Condition Pushdown) icpMySQL 中一个常用的优化,尤其是当MySQL需要从一张表里检索数据时。 ICP(Index Condition Pushdown)是 MySQL 利用索引(二级索引)元组和筛字段在索引中的 WHERE 条件从表中提取数据记录的一种优化操作。 ICP 的思想是:存储引擎在访问索引的时候检查筛选字段在索引中的 where 条件,如果索引元组中的数据不满足推送的索引条件,那么就过滤掉该条数据记录。 ICP (优化器)尽

小洪帽i的博客 1084

mysql mrr icp_【mysql】关于ICPMRRBKA特性

Index Condition Pushdown (ICP)是mysql使用索引从表中检索行数据的一种优化方式,从mysql5.6开始支持,mysql5.6之前,存储引擎会通过遍历索引定位基表中的行,然后返回给Server层,再去为这些数据行进行WHERE后的条件的过滤。mysql 5.6之后支持ICP后,如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索...

weixin_29728529的博客 115

mysql icp_【mysql】关于ICPMRRBKA特性

Index Condition Pushdown (ICP)是mysql使用索引从表中检索行数据的一种优化方式,从mysql5.6开始支持,mysql5.6之前,存储引擎会通过遍历索引定位基表中的行,然后返回给Server层,再去为这些数据行进行WHERE后的条件的过滤。mysql 5.6之后支持ICP后,如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索...

weixin_29736885的博客 128

icp mysql_关于MysqlICPMRRBKA特性

一、ICP( Index_Condition_Pushdown)如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索引过滤,把满足的行从表中读取出。ICP能减少Server层访问存储引擎的次数和引擎层访问基表的次数。session级别设置:set optimizer_switch="index_condition_pushdown=on对于InnoDB表,I...

weixin_39957265的博客 197

mysql5.6 icp mrr bak_【mysql】关于ICPMRRBKA特性

Index Condition Pushdown (ICP)是mysql使用索引从表中检索行数据的一种优化方式,从mysql5.6开始支持,mysql5.6之前,存储引擎会通过遍历索引定位基表中的行,然后返回给Server层,再去为这些数据行进行WHERE后的条件的过滤。mysql 5.6之后支持ICP后,如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索...

weixin_42351910的博客 134

mysql】关于ICPMRRBKA特性

mysql】关于ICPMRRBKA特性 https://www.cnblogs.com/chenpingzhao/p/6720531.html 转载 一、Index Condition Pushdown(ICP) Index Condition Pushdown (ICP)是mysql使用索引从表中检索行数据的一种优化方式,从mysql5.6开始支持,mysql5.6之前,存储引擎会...

无双-放飞的自我 262

mysql5.6 icp mrr bak_ICPMRRBKA特性

ICP的目标是减少从基表中读取操作的数量,从而降低IO操作对于InnoDB表,ICP只适用于辅助索引当使用ICP优化时,执行计划的Extra列显示Using indexcondition提示数据库配置 optimizer_switch="index_condition_pushdown=on”;使用场景举例辅助索引INDEX (a, b, c)SELECT * FROM peopleWHERE a...

weixin_39726697的博客 138

一文看懂MySQL索引下推(ICP)

本文主要介绍MySQL索引下推(ICP)和索引下推底层原理

weixin_46425661的博客 3861

MySQL 优化器 ICP 下推(让你彻底理解 ICP

ICP(Index Condition Pushdown,索引下推),是 MySQL 5.6 版本推出的功能,用于优化 MySQL 查询。ICP 可以减少存储引擎查询回表的次数以及 MySQL server 层访问存储引擎的次数。ICP 的目标是减少整行记录读取的次数,从而减少 I/O 操作。

热爱数据库的小胖 1709

MySQL中为啥引入批量键访问(Batch Key Access, BKA

MySQL 在某些情况下用于优化JOIN操作的一种技术,特别是在通过索引进行JOIN时,它能有效减少查询的随机 I/O。批量键访问优化通过将一批主键或索引键一次性发送给存储引擎来查找匹配的行,而不是逐行处理。这种方式可以有效利用数据库的缓存和减少 I/O 开销。在传统的(嵌套循环连接)中,MySQL 会逐行处理外部表的每一行,并针对每一行去内部表查找对应的匹配记录。这样会导致很多随机 I/O 操作,从而影响性能。

hikktn的博客 934

MySQL索引下推(ICP

索引下推(Index Condition Pushdown)ICPMySQL5.6之后推出的查询优化策略,主要的核心点就在于把本来由Server层做的索引条件检查下推给存储引擎来做,以降低回表和访问存储引擎的次数,提高查询效率。

m0_49151953的博客 562

MySQL中,索引下推的原理是什么?

索引下推(Index Condition Pushdown)是 MySQL 中一项重要的查询优化技术,通过将部分查询条件下推到索引扫描阶段,减少不必要的数据页访问,显著提升查询性能。理解 ICP 的工作原理、应用场景及其与其他优化技术的关系,对于数据库性能优化具有重要意义。在实际应用中,充分利用 ICP 需要合理设计索引结构,特别是联合索引和覆盖索引,确保查询条件能够在索引层被有效评估。同时,结合查询重写、缓存优化、分区表设计等多种优化手段,可以进一步提升 MySQL 的查询效率。

Java架构师之路的博客 1294

mysql ICP优化的原理

概述 今天主要介绍一下mysqlICP特性,可能很多人都没听过,这里用一个实验来帮助大家加深一下理解。 一、Index Condition Pushdown Index Condition Pushdown (ICP)是MySQL用索引去表里取数据的一种优化。如果禁用ICP,引擎层会穿过索引在基表中寻找数据行,然后返回给MySQL Server层,再去为这些数据行进行WHERE后的条件的过滤。 ICP启用,如果部分WHERE条件能使用索引中的字段,MySQL Server 会把这部分下推到引擎层.

papaya的博客 991

滚珠丝杠选型和电机选型计算.doc

滚珠丝杠选型和电机选型计算.doc

上一篇: MySQL索引提示
下一篇: innodb新特性之buffer pool预热
StevenBeijing
博客等级 码龄14年 4粉丝 279原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值