【背景】sql
对于关系数据库中的一张表,一般来讲数据页面的总大小要比较某一个索引占用的页面要大的多(上面说的索引是不包涵主键索引的);数据库
更进一步咱们能够推导出,若是咱们经过读索引就能解决问题,那么它相比读数据页来讲要廉价的多;总体上看数据库会尽量的经过oop
读索引就解决问题。测试
【index_merge是什么】优化
为了说明index_merge是什么、这里仍是从一个例子开始;假设数据库存在以下内容spa
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) );
表中的数据以下code
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;server
给这两个id的集合作一下交集;这样就找到了全部知足条件的行id,最后回表把对应的行给查询出来;若是MySQL这样作的话blog
在索引页面数理远远小于数据页面数量的状况下是有节约成功的优点的索引
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优化快多少呢】
一、测试启用index_merge状况下40w行数据时查询的用时
select name,age from person where name='tom' and age=17; Empty set (0.08 sec)
二、关闭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'; --: 退出从新链接(这样刚才的设置就生效了)
三、在没有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的原理能够知在数据理更大的
状况下优化的效果会更加明显
【个人我的站点】