MySQL Index--BAK和MRR演示

Posted 笑东风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL Index--BAK和MRR演示相关的知识,希望对你有一定的参考价值。

搭建测试环境演示BKA和MRR特性

建表语句:

## 创建测试表tb1和tb2
CREATE TABLE `tb1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_c1` (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

CREATE TABLE `tb2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_c2` (`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

## 向测试表tb1和tb2插入30万数据
## 表tb1001的id值自增
INSERT INTO tb1(c1,c2) SELECT id,id FROM tb1001;
INSERT INTO tb1(c1,c2) SELECT id,id FROM tb1001;

 

测试SQL:

SELECT * 
FROM tb1
INNER JOIN tb2
ON tb1.c1 = tb2.C2
WHERE tb1.c1>100 AND tb1.c1<200

对应执行计划:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb1
   partitions: NULL
         type: range
possible_keys: IDX_C1
          key: IDX_C1
      key_len: 5
          ref: NULL
         rows: 99
     filtered: 100.00
        Extra: Using index condition; Using MRR
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb2
   partitions: NULL
         type: ref
possible_keys: IDX_C2
          key: IDX_C2
      key_len: 5
          ref: demodb.tb1.C1
         rows: 1
     filtered: 100.00
        Extra: Using join buffer (Batched Key Access)
2 rows in set, 1 warning (0.00 sec)

对应执行计划(JSON):

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "258.44"
    },
    "nested_loop": [
      {
        "table": {
          "table_name": "tb1",
          "access_type": "range",
          "possible_keys": [
            "IDX_C1"
          ],
          "key": "IDX_C1",
          "used_key_parts": [
            "C1"
          ],
          "key_length": "5",
          "rows_examined_per_scan": 99,
          "rows_produced_per_join": 99,
          "filtered": "100.00",
          "index_condition": "(((`demodb`.`tb1`.`C1` > 100) and (`demodb`.`tb1`.`C1` < 200)) and (`demodb`.`tb1`.`C1` is not null))",
          "using_MRR": true,
          "cost_info": {
            "read_cost": "119.81",
            "eval_cost": "19.80",
            "prefix_cost": "139.61",
            "data_read_per_join": "1K"
          },
          "used_columns": [
            "ID",
            "C1",
            "C2"
          ]
        }
      },
      {
        "table": {
          "table_name": "tb2",
          "access_type": "ref",
          "possible_keys": [
            "IDX_C2"
          ],
          "key": "IDX_C2",
          "used_key_parts": [
            "C2"
          ],
          "key_length": "5",
          "ref": [
            "demodb.tb1.C1"
          ],
          "rows_examined_per_scan": 1,
          "rows_produced_per_join": 99,
          "filtered": "100.00",
          "using_join_buffer": "Batched Key Access",
          "cost_info": {
            "read_cost": "99.02",
            "eval_cost": "19.80",
            "prefix_cost": "258.44",
            "data_read_per_join": "1K"
          },
          "used_columns": [
            "ID",
            "C1",
            "C2"
          ]
        }
      }
    ]
  }
}

 

执行计划伪代码(个人理解):

c1_condition=((`demodb`.`tb1`.`C1` > 100) 
    and (`demodb`.`tb1`.`C1` < 200) 
    and (`demodb`.`tb1`.`C1` is not null))

tb1_mrr_buffer=new buffer(@@read_rnd_buffer_size)

tb1_search_result=[]
for each tb1_index_row(c1,id) in(range scan tb1.idx_c1 with c1_condition):
    if tb1_mrr_buffer is not full or tb1_index_row is last row:
        tb1_mrr_buffer.append(tb1_index_row(c1,id))
    else## using mrr
        tb1_mrr_buffer.sort_by(id)
        for tb1_index_row(id,c1) in tb1_mrr_buffer:
            tb1_data_row(id,c1,c2)=(search index tb1.priamry_key with id=tb1_index_row.id)
            tb1_search_result.append(tb1_data_row)
tb1_mrr_buffer.dispose()
tb1_bka_buffer
=new buffer(@@join_buffer_size) tb1_tb2_join_result=[] for each tb1_data_row(id,c1,c2) in tb1_search_result: if tb1_bka_buffer is not full or tb1_data_row is last row: tb1_bka_buffer.append(tb1_data_row(id,c1,c2)) else## using bka tb1_bka_buffer.sort_by(c1) for tb1_data_row(id,c1,c2) in tb1_bka_buffer: for tb2_index_row(c2,id) in (range scan tb2.idx_c2 where c2=tb1_data_row.c1) tb2_data_row(id,c1,c2)=(search index tb2.priamry_key with id=tb2_index_row.id) join_row=(tb1_data_row(id,c1,c2),tb2_data_row(id,c1,c2)) tb1_tb2_join_result.append(join_row) tb1_bka_buffer.dispose()
return tb1_tb2_join_result

PS1:MRR特性使用的buffer大小受限于参数read_rnd_buffer_size,而BKA使用的buffer大小受限于join_buffer_size

以上是关于MySQL Index--BAK和MRR演示的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 优化--持续整理

0926mysql中MRR的用法

MRR和ICP

MRR和ICP

浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化

浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化