作者:蒋乐兴

MySQL DBA,擅长 python 和 SQL,目前维护着 github 的两个开源项目:mysqltools 、dbmc 以及独立博客:https://www.sqlpy.com。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

MRR 要解决的问题

MRR 是 MySQL 针对特定查询的一种优化手段。假设一个查询有二级索引可用,读完二级索引后要回表才能查到那些不在当前二级索引上的列值,由于二级索引上引用的主键值不一定是有序的,因此就有可能造成大量的随机 IO,如果回表前把主键值给它排一下序,那么在回表的时候就可以用顺序 IO 取代原本的随机 IO。

环境准备

为了实验我们要准备一下表结构和数据。

-- 创建表

mysql> show create table t;

+----------------------------------------------------------------------+

| Table | Create Table |

+----------------------------------------------------------------------+

| t | CREATE TABLE `t` (

`id` int NOT NULL AUTO_INCREMENT,

`i0` int NOT NULL,

`i1` int NOT NULL,

`i2` int NOT NULL,

`i3` int NOT NULL,

`c0` varchar(128) NOT NULL,

`c1` varchar(128) NOT NULL,

`f0` float NOT NULL,

`f1` float NOT NULL,

PRIMARY KEY (`id`),

KEY `idx_i0` (`i0`)

) ENGINE=InnoDB

+----------------------------------------------------------------------+

1 row in set (0.00 sec)

-- 造数据

mysql> select count(*) from t;

+----------+

| count(*) |

+----------+

| 1120000 |

+----------+

1 row in set (0.77 sec)

--

update t set i0 = id % 100;

MRR 的优化效果

1. 有 MRR 优化(Using MRR)时 SQL 的耗时情况。

mysql> explain select i0,i3 from t where i0 between 1 and 2;

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+

| 1 | SIMPLE | t | NULL | range | idx_i0 | idx_i0 | 4 | NULL | 43968 | 100.00 | Using index condition; Using MRR |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+

1 row in set, 1 warning (0.00 sec)

mysql> select i0,i3 from t where i0 between 1 and 2;

22400 rows in set (0.80 sec)

2. 关闭 MRR 优化。

set optimizer_switch = 'index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=off,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on';

mysql> explain select i0,i3 from t where i0 between 1 and 2;

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+

| 1 | SIMPLE | t | NULL | range | idx_i0 | idx_i0 | 4 | NULL | 43968 | 100.00 | Using index condition |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+

1 row in set, 1 warning (0.00 sec)

mysql> select i0,i3 from t where i0 between 1 and 2;

22400 rows in set (2.56 sec)结论

就刚才的测试场景开启 MRR 优化可以得到 3 倍的性能提升。

MRR 的优化器参数调整

如果想关闭 MRR 优化的话,就要把优化器开关 mrr 设置为 off。

默认只有在优化器认为 MRR 可以带来优化的情况下才会走 MRR,如果你想不管什么时候能走 MRR 的都走 MRR 的话,你要把 mrr_cost_based 设置为 off,不过最好不要这么干,因为这确实是一个坑,MRR 不一定什么时候都好,全表扫描有时候会更加快,如果在这种场景下走 MRR 就完成了。

开启 MRR 关闭基于开销的优化。

-- mrr=on,mrr_cost_based=off

set optimizer_switch = 'index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=off,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on';

mysql> explain select i0,i3 from t where i0 between 1 and 10;

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

| 1 | SIMPLE | t | NULL | range | idx_i0 | idx_i0 | 4 | NULL | 218492 | 100.00 | Using index condition; Using MRR |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

1 row in set, 1 warning (0.00 sec)

select i0,i3 from t where i0 between 1 and 10;

112000 rows in set (4.86 sec)

开启 MRR 开启基于开销的优化。

-- mrr=on,mrr_cost_based=on

set optimizer_switch = 'index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on';

mysql> explain select i0,i3 from t where i0 between 1 and 10;

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

| 1 | SIMPLE | t | NULL | ALL | idx_i0 | NULL | NULL | NULL | 1121902 | 19.48 | Using where |

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

1 row in set, 1 warning (0.00 sec)

mysql> select i0,i3 from t where i0 between 1 and 10;

112000 rows in set (1.52 sec)

可以看到当 mrr_cost_based = OFF 的情况下用时 4.86s,mrr_cost_based = ON 的情况下用时 1.52s,总的来说 mrr_cost_based 是非常关键的建议始终打开。

MRR 的参数优化

MRR 要把主键排个序,这样之后对磁盘的操作就是由顺序读代替之前的随机读。从资源的使用情况上来看就是让 CPU 和内存多做点事,来换磁盘的顺序读。然而排序是需要内存的,这块内存的大小就由参数 read_rnd_buffer_size 来控制。

read_rnd_buffer_size 太小无法启用 MRR 功能。

mysql> select @@read_rnd_buffer_size;

+------------------------+

| @@read_rnd_buffer_size |

+------------------------+

| 262144 |

+------------------------+

1 row in set (0.00 sec)

mysql> explain select i0,i3 from t where i0 between 1 and 12;

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

| 1 | SIMPLE | t | NULL | ALL | idx_i0 | NULL | NULL | NULL | 1121902 | 23.57 | Using where |

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+

1 row in set, 1 warning (0.00 sec)

放大 read_rnd_buffer_size 让 MySQL 有足够的资源用于 MRR 。

mysql> set read_rnd_buffer_size = 32 * 1024 * 1024;

Query OK, 0 rows affected (0.00 sec)

mysql> explain select i0,i3 from t where i0 between 1 and 12;

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

| 1 | SIMPLE | t | NULL | range | idx_i0 | idx_i0 | 4 | NULL | 264436 | 100.00 | Using index condition; Using MRR |

+----+-------------+-------+------------+-------+---------------+--------+---------+------+--------+----------+----------------------------------+

1 row in set, 1 warning (0.00 sec)

mysql mrr_cost_based_技术分享 | 用好 MySQL 的 MRR 优化器相关推荐

  1. mysql数据库j电子课件,MYSQL数据库技术分享PPT演示课件

    <MYSQL数据库技术分享PPT演示课件>由会员分享,可在线阅读,更多相关<MYSQL数据库技术分享PPT演示课件(29页珍藏版)>请在人人文库网上搜索. 1.数据库技术分享, ...

  2. mysql mts_技术分享 | 回顾 MySQL 的 MTS

    作者:洪斌 爱可生南区负责人兼技术服务总监,MySQL ACE,擅长数据库架构规划.故障诊断.性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融.运营商.互联网等行业客户提供 ...

  3. mysql+odbc+ado_MFC ado+mysql+odbc技术分享

    第一步:建立数据库 假设有一个sql文件 mysql>use dbname;                   //创建一个数据库名为dbname的数据库(空数据库) mysql>set ...

  4. mysql dbuild_config_技术分享 | MySQL Test 初探

    什么是 MySQL Test? MySQL Test 是 MySQL 发行版本中集成 all-in-one 测试框架,用于做 mysql 服务的单元,回归和一致性测试,并提供了运行单元测试和创建新单元 ...

  5. mysql tcmalloc_技术分享 | tcmalloc解决mysqld实例引发的cpu过高问题

    原创:任坤作者简介 任坤,现居珠海,先后担任专职 Oracle 和 MySQL DBA,现在主要负责 MySQL.mongoDB 和 Redis 维护工作. 背景 MySQL 版本:5.6.29,普通 ...

  6. 技术分享 | 浅谈 MySQL 的临时表和临时文件

    作者:姚嵩 爱可生南区交付服务部经理,爱好音乐,动漫,电影,游戏,人文,美食,旅游,还有其他.虽然都很菜,但毕竟是爱好. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请 ...

  7. mysql relay_技术分享 | MySQL:产生大量小 relay log 的故障一例

    作者:高鹏 文章末尾有他著作的<深入理解 MySQL 主从原理 32 讲>,深入透彻理解 MySQL 主从,GTID 相关技术知识. 源码版本:5.7.22 水平有限,如有误请谅解 本文建 ...

  8. MySQL mdl导入_技术分享 | 深入理解 MySQL MDL Lock

    作者:高鹏(网名八怪) 文章末尾有他著作的<深入理解 MySQL 主从原理 32 讲>,深入透彻理解 MySQL 主从,GTID 相关技术知识. 本文来源:转载自公众号-mysql cod ...

  9. mysql 1280_技术分享 | MySQL 一次奇怪的故障分析

    一.问题来源 这是一个朋友问我的典型案例.整个故障现象表现为,MySQL 数据库频繁的出现大量的请求不能响应.下面是一些他提供的证据: 1. show processlist从状态信息来看出现如下情况 ...

最新文章

  1. 面试题:如何理解 Linux 的零拷贝技术?
  2. Twitter 广告平台实时计费系统的架构增强之道
  3. VTK:给定颜色,找到对比色用法实战
  4. javascript学习系列(15):数组中的lastIndexOf方法
  5. Idea Marketplace 加载很慢 加载不出来
  6. 数据千万条,备份第一条:VFEmail被擦除所有数据面临关停
  7. Oracle的where子句
  8. 【BZOJ1085】迭代加深+启发式搜索
  9. 理解Java - JDK动态代理原理
  10. Android 表单之 EditText(输入框)详解
  11. Windows之IOCP
  12. 分页存储管理系统中内存有效访问时间的计算
  13. 正点原子Linux开发板实现WiFi开机自动连接
  14. Markdown:插入图片和图注
  15. Latex文档中 插入符号和编号
  16. 【财务_会计3_1】会计科目的概念
  17. GitQ 导读: 为什么 GitHub ?
  18. 传奇服务器系统版本,[资料]服务端详细解释
  19. java web 组态,Java:Eclipse中使用WTP开发Web项目
  20. 计算机分子模拟的意义包括,计算机分子模拟

热门文章

  1. 工作生活记-积极主动
  2. 计算机中文输入法教案,中文输入法(一教案.doc
  3. python中匿名函数的关键字_Python匿名函数(lambda函数)
  4. mysql insert id菜鸟_MySQL 插入数据
  5. 怎么下载在阿里云平台注册域名的域名证书
  6. Anaconda 使用简介
  7. Redis实战 - 09 Redis BitMaps 实现用户签到,统计签到次数,统计签到情况等功能
  8. 20220423draw
  9. 2017第九届中国国际物联网博览会(春季展)会刊(参展商名录)
  10. 廊坊公立中专计算机学校有哪些,廊坊中专学校排名