背景

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

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

  读索引就解决问题。

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. BZOJ-2-4870: [Shoi2017]组合数问题 矩阵优化 DP

    就 是 要 我 们 从  n k  件 物 品 里 面 选 出 若 干 件,使 得 其 数 量 模 k 等 于 r 的 方 案 数 . dp方程 f [ i , j ] 表示前 i 件物品拿了若干件使 ...

  2. Xamarin Essentials教程打开文件

    Xamarin Essentials教程打开文件 FileSystem类的OpenAppPackageFileAsync()方法可以用来打开App包中特定的文件,其语法形式如下: public sta ...

  3. C#常用字符串函数

    Compare 比较字符串的内容,考虑文化背景(场所),确定某些字符是否相等 CompareOrdinal 与Compare一样,但不考虑文化背景 Format 格式化包含各种值的字符串和如何格式化每 ...

  4. BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)

    BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...

  5. BZOJ.3653.谈笑风生(长链剖分/线段树合并/树状数组)

    BZOJ 洛谷 \(Description\) 给定一棵树,每次询问给定\(p,k\),求满足\(p,a\)都是\(b\)的祖先,且\(p,a\)距离不超过\(k\)的三元组\(p,a,b\)个数. ...

  6. Stm32常见英文缩写

    Stm32常见英文缩写 https://wenku.baidu.com/view/4b9c2eee5022aaea998f0f5b.html STM32嵌入式开发常见缩写 https://wenku. ...

  7. [CC-MINXOR]XOR Minimization

    [CC-MINXOR]XOR Minimization 题目大意: 有一个长度为\(n\)的数列\(A_{1\sim n}\).\(q\)次操作,操作包含以下两种: 询问\(A_{l\sim r}\) ...

  8. docker 进入容器的mongodb

    docker search mongo docker pull mongo docke run -p 27017:27017 -v $PWD/db:/data/db -d  --name mymong ...

  9. Spring MVC ,使用mvc:resources标签后,处理器无法被访问

    在SpringMVC的配置文件中添加了<mvc:resources mapping="/img/**" location="/img/"/>以便处理 ...

  10. innerHTML innerText与outerHTML间的区别

    innerHTML与innerText及outerHTML间的区别最容易使初学者搞混淆,为了更好的使读者区分开.下面我就通过一个demo来解释: 代码: <!DOCTYPE html>&l ...