MySQL优化:单索引的选择-index_merge

1.多个单索引

where子句后有多个查询条件,MySQL 5.1以前即使分别为每个条件建立索引,查询优化器也只会选择其中一个区分度高索引。笔者使用5.7.20,以下分析均基于此版本,不同版本的MySQL查询优化器给出的结果存在差异。下面开始分情况讨论MySQL查询优化器给出的索引结果。

  • where子句有两个个and条件分别且三个字段都有索引
mysql> EXPLAIN SELECT * FROM order t WHERE t.PrdModel = 'NX549J' AND t.Destination = '国内' AND t.OEM = '福盛创新'; 
+----+-------------+-------+------------+-------------+--------------------------+--------------+---------+------+------+----------+--------------------------------------------+
| id | select_type | table | partitions | type        | possible_keys            | key          | key_len | ref  | rows | filtered | Extra                                      |
+----+-------------+-------+------------+-------------+--------------------------+--------------+---------+------+------+----------+--------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | index_merge | PrdModel,Destination,OEM | OEM,PrdModel | 153,153 | NULL |  614 |    50.00 | Using intersect(OEM,PrdModel); Using where |
+----+-------------+-------+------------+-------------+--------------------------+--------------+---------+------+------+----------+--------------------------------------------+
1 row in set, 1 warning (0.00 sec)


mysql> EXPLAIN SELECT * FROM order t WHERE t.PrdModel = 'NX549J' AND t.Destination = '国内' AND t.OEM = 'XXX技术有限公司'; 
+----+-------------+-------+------------+-------------+--------------------------+----------------------+---------+------+--------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type        | possible_keys            | key                  | key_len | ref  | rows   | filtered | Extra                                              |
+----+-------------+-------+------------+-------------+--------------------------+----------------------+---------+------+--------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | index_merge | PrdModel,Destination,OEM | PrdModel,Destination | 153,153 | NULL | 320463 |    50.00 | Using intersect(PrdModel,Destination); Using where |
+----+-------------+-------+------------+-------------+--------------------------+----------------------+---------+------+--------+----------+----------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

上例告诉我们实际的索引应用的index_merge,从三索引中选其二,奇怪的是每次选择结果并不是固定,第一次选择intersect(OEM,PrdModel),第二次选择intersect(PrdModel,Destination),尝试从区分度的角度查找原因,上例中三个索引的区分度分别为PrdModel(35045),Destination(22982),OEM(6195)。发现并不是简单的从区分度最高的索引选其二。那么索引合并选择的依据是什么呢?下面尝试从合并的复杂度方面比较:

索引/取值(记录数)/参数 PrdModel Destination OEM
intersect(PrdModel,Destination) NX549J(320147) 国内(8077050) XXX技术有限公司(5418791)
intersect(OEM,PrdModel) NX549J(320147) 国内(8077050) 福盛创新(11094)
intersect(PrdModel,Destination) NX549J(320147) 国内(8077050) is not null (21800063)
intersect(PrdModel,OEM) NX549J(320147) 国内(8077050) is null (537463)
  • 下面借助 官网文档 尝试理解index_merge的使用及选择机制。
    index_merge用在范围查询中,然后尝试合并多个索引检索的结果。笔者分别尝试两个、三个、四个条件的索引发现,index_merge只会选择其二合并索引,这一点官方没有特别说明。官方提到,index_merge只能扫描单表,不能跨表扫描。index merge: 同一个表的多个索引的范围扫描可以对结果进行合并,合并方式分为三种:union, intersection, 以及它们的组合(先内部intersect然后在外面union)。
    官方给出了四个例子。

SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;
SELECT * FROM tbl_name WHERE (key1 = 10 OR key2 = 20) AND non_key = 30;
SELECT * FROM t1, t2 WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%') AND t2.key1 = t1.some_col;
SELECT * FROM t1, t2 WHERE t1.key1 = 1 AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2);

经过测试,发现前三种能够得到index_merge,第四种情况看起来有点怪,两个连表条件,一个和一个查询条件,并不能使用index_merge。

  • 注意,下面是官方给出的建议,where后的条件写的比较复杂时,可能引起查询优化器的错误选择索引,应遵循以下原则:

(x AND y) OR z => (x OR z) AND (y OR z)
(x OR y) AND z => (x AND z) OR (y AND z)

  • index merge 之 intersect
    index intersect merge就是多个索引条件扫描得到的结果进行交集运算,结果如下:

key_part1=const1 AND key_part2=const2 ... AND key_partN=constN

  • index merge 之 union
    index uion merge就是多个索引条件扫描,对得到的结果进行并集运算,显然是多个条件之间进行的是 OR 运算。

key1 = 1 OR key2 = 2 OR key3 = 3;

  • index merge 之 Sort-Union
    简言之,就是需要先取交集再取并集,如多个OR的范围查询,可能有重复的记录,需要先取并集再取交集。

SELECT * FROM tbl_name WHERE key_col1 < 10 OR key_col2 < 20;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容