MySQL优化器 --- index_merge
【背景】
对于关系数据库中的一张表,通常来说数据页面的总大小要比较某一个索引占用的页面要大的多(上面说的索引是不包涵主键索引的);
更进一步我们可以推导出,如果我们通过读索引就能解决问题,那么它相比读数据页来说要廉价的多;整体上看数据库会尽可能的通过
读索引就解决问题。
【index_merge是什么】
为了说明index_merge是什么、这里还是从一个例子开始;假设数据库存在如下内容
create table person (id int not null auto_increment primary key,
name varchar(8) default null,
age tinyint default null,
key idx_person_name (name),
key idx_person_age (age)
);
表中的数据如下
select * from person;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | tom | 16 |
| 2 | jerry | 17 |
| 3 | neeky | 3 |
+----+-------+------+
3 rows in set (0.00 sec)
下面的这条SQL语句事实上可以这样做,读取idx_person_name找到name='tom'的行id,读取idx_person_age找到age=17的行id;
给这两个id的集合做一下交集;这样就找到了所有满足条件的行id,最后回表把对应的行给查询出来;如果MySQL这样做的话
在索引页面数理远远小于数据页面数量的情况下是有节约成功的优势的
select name,age from person where name='tom' and age=17;
事实上MySQL会不会这样干呢?对于这个还是要看执行记录比较靠普;从下面的执行计划可以看出MySQL选择了只用
idx_person_name这一个索引,从innodb中捞到数据后在server层过滤的方式来完成查询。明显没有用到index_merge
explain select name,age from person where name='tom' and age=17;
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | person | NULL | ref | idx_person_name,idx_person_age | idx_person_name | 67 | const | 1 | 33.33 | Using where |
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec
从上面的分析我们可以知道用不用index_merge优化,不光是看可不可以用理加重要的是看代价是否合理;为了让MySQL知道索引页面的数量要远远小于
数据页面的数量,我要在表中多插入一些数据(复制执行下面的语句)
insert into person(name,age) select name,age from person; -- 执行n次
select count(*) from person;
+----------+
| count(*) |
+----------+
| 393216 |
+----------+
1 row in set (0.05 sec)
在数据量差不多40w的情况下我们再看一下优化器的选择
explain select name,age from person where name='tom' and age=17;
+----+-------------+--------+------------+-------------+--------------------------------+--------------------------------+---------+------+-------+----------+---------------------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------------+--------------------------------+--------------------------------+---------+------+-------+----------+---------------------------------------------------------------------------+
| 1 | SIMPLE | person | NULL | index_merge | idx_person_name,idx_person_age | idx_person_name,idx_person_age | 67,2 | NULL | 98237 | 100.00 | Using intersect(idx_person_name,idx_person_age); Using where; Using index |
+----+-------------+--------+------------+-------------+--------------------------------+--------------------------------+---------+------+-------+----------+---------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
【用了Index_merge优化会比没有用index_merge优化快多少呢】
1、测试启用index_merge情况下40w行数据时查询的用时
select name,age from person where name='tom' and age=17;
Empty set (0.08 sec)
2、关闭MySQL数据库对index_merge的优化
set @@global.optimizer_switch='index_merge=off,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'; --: 退出重新连接(这样刚才的设置就生效了)
3、在没有index_merge的情况下发起查询
explain select name,age from person where name='tom' and age=17;
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+--------+----------+-------------+
| 1 | SIMPLE | person | NULL | ref | idx_person_name,idx_person_age | idx_person_name | 67 | const | 196474 | 50.00 | Using where |
+----+-------------+--------+------------+------+--------------------------------+-----------------+---------+-------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec) -- 从执行计划上可以看出index_merge关闭了 select name,age from person where name='tom' and age=17;
Empty set (0.34 sec)
【总结】
对比开启和关闭index_merge,在数据量为40w这个量级的表上,开启优化相比不开有4倍以上的优化成绩。由index_merge的原理可以知在数据理更大的
情况下优化的效果会更加明显
【我的个人站点】
MySQL优化器 --- index_merge的更多相关文章
- 0104探究MySQL优化器对索引和JOIN顺序的选择
转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...
- 机智的MySQL优化器 --- is null
[介绍] 工作的越久越到的的问题越多,就越是觉得一些“老话”历久弥新:由于最近的学习计划是深入的学习一遍MySQL优化器:学习过程中的一些成果 也会发布到这里,一来是为了整理自己已经知道的和新学到的, ...
- MySQL优化器功能开关optimizer_switch
MySQL 8.0新增特性 use_invisible_indexes:是否使用不可见索引,MySQL 8.0新增可以创建invisible索引,这一开关控制优化器是否使用invisible索引,on ...
- 数据库 mysql 优化器原理
MySQL查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行. 你的最终目标是提交SELECT语句查找数据行,而不是排除数据行.优化器试图排除数据 ...
- MySQL优化器cost计算
记录MySQL 5.5上,优化器进行cost计算的方法. 第一篇: 单表的cost计算 数据结构: 1. table_share: 包含了表的元数据,其中索引部分: key_info:一个key的结构 ...
- 《Mysql - 优化器是如何选择索引的?》
一:概念 - 在 索引建立之后,一条语句可能会命中多个索引,这时,索引的选择,就会交由 优化器 来选择合适的索引. - 优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句. 二: ...
- 如何干涉MySQL优化器使用hash join
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 实验 总结 前言 数据库的优化器相当于人类的大 ...
- MySQL优化器不使用索引的情况
优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 ; 通过SHOW ...
- MySQL 优化之 index_merge (索引合并)
深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where ...
随机推荐
- UVa11988 Broken Keyboard 损坏的键盘【list】
题目链接:https://vjudge.net/problem/UVA-11988 题目大意: 键盘的home键和end键出现了问题. 在输入一段文本时,home键或end键可能会自动被按下,home ...
- linux 学习笔记六 tail 命令
#tail -f -n100 catalina.out 含义 从文件尾部监视catalina.out 文件 要看文件尾部100行 #tail -f -n100 catalina,out > ...
- angular笔记_4(函数)
angular.isString();是否字符串 angular.isNumber();是否数字 angular.isArray();是否数组 angular.isDate();是否日期/时间 ang ...
- Lock锁与Condition监视器(生产者与消费者)。
/*生产者与消费者第二次敲,本人表示很郁闷,以后要经常读这个 * Condition 将Object类中的监视器(wait notify notifyAll)分解成不同的对象.例如condition_ ...
- git解决Could not execute editor
我是安装k-vim后出现了这个问题,可能是vim的某些插件引起的 配置git的编辑器可解决: git config --global core.editor "/usr/bin/vim&qu ...
- 全球第一款纯数据GPRS模块 有方M590 概述
更多精彩请到http://blog.tuzhuke.info/?cat=30 M590为全球第一款纯数据GPRS模块,专注数据收发功能,GPRS数据以及短信数据.没有电话语音功能,可以能够拨打或者接听 ...
- Django session 源码流程
流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...
- win7生成ssh key配置到gitlab
测试服务上使用ip访问gitlab,比如http://192.168.0.2/,创建用户并登陆后创建一个项目,比如git@gitlab.demo.com:demo/helloworld.git 如果想 ...
- Windbg SOS 加载技巧(.net framwork 2.0)
1.打开windbg,加载dump.使用命令确定dump的clr版本:lm vm mscorwks 或者lm vm clr(!eeversion可以查看加载后的sos版本) 2.找到对应的mscorw ...
- swal() 弹出层的用法
swal()方法是一个提示框: swal({ title: "", text: "请扫描用户手机上的付款码", type: "input", ...