背景

  对于关系数据库中的一张表,通常来说数据页面的总大小要比较某一个索引占用的页面要大的多(上面说的索引是不包涵主键索引的);

  更进一步我们可以推导出,如果我们通过读索引就能解决问题,那么它相比读数据页来说要廉价的多;整体上看数据库会尽可能的通过

  读索引就解决问题。

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的原理可以知在数据理更大的

  情况下优化的效果会更加明显

我的个人站点

  www.sqlpy.com

MySQL优化器 --- index_merge的更多相关文章

  1. 0104探究MySQL优化器对索引和JOIN顺序的选择

    转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...

  2. 机智的MySQL优化器 --- is null

    [介绍] 工作的越久越到的的问题越多,就越是觉得一些“老话”历久弥新:由于最近的学习计划是深入的学习一遍MySQL优化器:学习过程中的一些成果 也会发布到这里,一来是为了整理自己已经知道的和新学到的, ...

  3. MySQL优化器功能开关optimizer_switch

    MySQL 8.0新增特性 use_invisible_indexes:是否使用不可见索引,MySQL 8.0新增可以创建invisible索引,这一开关控制优化器是否使用invisible索引,on ...

  4. 数据库 mysql 优化器原理

    MySQL查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行. 你的最终目标是提交SELECT语句查找数据行,而不是排除数据行.优化器试图排除数据 ...

  5. MySQL优化器cost计算

    记录MySQL 5.5上,优化器进行cost计算的方法. 第一篇: 单表的cost计算 数据结构: 1. table_share: 包含了表的元数据,其中索引部分: key_info:一个key的结构 ...

  6. 《Mysql - 优化器是如何选择索引的?》

    一:概念 - 在 索引建立之后,一条语句可能会命中多个索引,这时,索引的选择,就会交由 优化器 来选择合适的索引. - 优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句. 二: ...

  7. 如何干涉MySQL优化器使用hash join

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 实验 总结 前言 数据库的优化器相当于人类的大 ...

  8. MySQL优化器不使用索引的情况

    优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 ; 通过SHOW ...

  9. MySQL 优化之 index_merge (索引合并)

    深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where ...

随机推荐

  1. 记录一个chrome 65渲染的bug

    前段时间发现一个chrome 65+的BUG(chrome已更新到66,BUG仍然存在),一个元素同时使用了以下样式(失去焦点和css3的Z轴平移0deg),渲染异常 /*bug style*/ fi ...

  2. Django 学习第九天——请求与响应

    一.HttpRequest 对象: 服务器接收到http协议的请求后,会根据报文创建 HttpRequest 对象视图函数的第一个参数是HttpRequest 对象再django.http 模块中定义 ...

  3. react+typescript报错集锦<持续更新>

    typescript报错集锦 错误:Import sources within a group must be alphabetized.tslint(ordered-imports) 原因:impo ...

  4. EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型

    官方教程:https://docs.microsoft.com/en-us/aspnet/core/data/?view=aspnetcore-2.1 使用EF CodeFirst在MySql中创建新 ...

  5. Alpha(5/10)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...

  6. sql语句练习50题(Mysql版)

    表名和字段–1.学生表Student(s_id,s_name,s_birth,s_sex) –学生编号,学生姓名, 出生年月,学生性别–2.课程表Course(c_id,c_name,t_id) – ...

  7. g++ 动态库的编译及使用

    #ifndef __HELLO_H_ #define __HELLO_H_ void print(); #endif #include "hello.h" #include < ...

  8. R语言语法基础二

    R语言语法基础二 重塑数据 增加行和列 # 创建向量 city = c("Tampa","Seattle","Hartford"," ...

  9. 【二分】Producing Snow @Codeforces Round #470 Div.2 C

    time limit per test: 1 second memory limit per test: 256 megabytes Alice likes snow a lot! Unfortuna ...

  10. [Asp.net core]使用ssh命令发布asp.net core项目

    命令 # 移除之前发布的包 rm -rf ./.Publish rm -rf ./Wolfy.Blog.tar.gz # 编译并发布 将发布包打包在.Publish目录下 -o "../.P ...