HarmonyOS 鸿蒙Next:MySQL中为什么要使用索引合并(Index Merge)?

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:MySQL中为什么要使用索引合并(Index Merge)? 摘要:本文介绍了索引合并(Index Merge)包含的三种类型,即交集(intersection)、并集(union)和排序并集(sort-union),以及索引合并的实现原理、场景约束与通过案例验证的优缺点。

本文分享自华为云社区《【华为云MySQL技术专栏】MySQL中为什么要使用索引合并(Index Merge)?》,作者:武文斌。

在生产环境中,MySQL语句的where查询通常会包含多个条件判断,以AND或OR操作进行连接。然而,对一个表进行查询最多只能利用该表上的一个索引,其他条件需要在回表查询时进行判断(不考虑覆盖索引的情况)。当回表的记录数很多时,需要进行大量的随机IO,这可能导致查询性能下降。因此,MySQL 5.x 版本推出索引合并(Index Merge)来解决该问题。

本文将基于MySQL8.0.22版本对MySQL的索引合并功能、实现原理及场景约束进行详细介绍,同时也会结合原理对其优缺点进行浅析,并通过例子进行验证。

什么是Index Merge?

索引合并是通过对一个表同时使用多个索引进行条件扫描,并将满足条件的多个主键集合取交集或并集后再进行回表,可以提升查询效率。

索引合并主要包含交集(intersection),并集(union)和排序并集(sort-union)三种类型:

  • intersection:将基于多个索引扫描的结果集取交集后返回给用户
  • union:将基于多个索引扫描的结果集取并集后返回给用户
  • sort-union:与union类似,不同的是sort-union会对结果集进行排序,随后再返回给用户

MySQL提供了四个开关(index_merge、index_merge_intersection、index_merge_union以及index_merge_sort_union)对上述三种索引合并类型提供支持,可以通过修改optimizer_switch系统参数中的四个开关标识来控制索引合并特性的使用。

假设创建表T,并插入如下数据:

CREATE TABLE T(
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int NOT NULL,
  `b` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`) USING BTREE,
  KEY `idx_b` (`b`) USING BTREE
)ENGINE=InnoDB AUTO_INCREMENT=1;

INSERT INTO T (a, b) VALUES (1, 'A'), (2, 'B'),(3, 'C'),(4, 'B'),(1, 'C');

默认情况下,四个开关均为开启状态。如果需要单独使用某个合并类型,需设置index_merge=off,并将相应待启用的合并类型标识(例如,index_merge_sort_union)设置为on。

开关开启后,可通过EXPLAIN执行计划查看当前查询语句是否使用了索引合并。

Index Merge原理

1. Index Merge Intersection

Index Merge Intersection会在使用到的多个索引上同时进行扫描,并取这些扫描结果的交集作为最终结果集。

以“SELECT * FROM T WHERE a=1 AND b=‘C’;”语句为例:

  • 未使用索引合并时,MySQL利用索引idx_a获取到满足条件a=1的所有主键id,根据主键id进行回表查询到相关记录,随后再使用条件b='C’对这些记录进行判断,获取最终查询结果。

  • 使用索引合并时,MySQL分别利用索引idx_a和idx_b获取满足条件a=1和b='C’的主键id集合setA和setB。随后取setA和setB中主键id的交集setC,并使用setC中主键id进行回表,获取最终查询结果。

2. Index Merge Union

Index Merge Union会在使用到的多个索引上同时进行扫描,并取这些扫描结果的并集作为最终结果集。

以“SELECT * FROM T WHERE a=1 OR b=‘B’;”语句为例:

  • 未使用索引合并时,MySQL通过全表扫描获取所有记录信息,随后再使用条件a=1和b='B’对这些记录进行判断,获取最终查询结果。

  • 使用索引合并算法时,MySQL分别利用索引idx_a和idx_b获取满足条件a=1和b='B’的主键id集合setA和setB。随后,取setA和setB中主键id的并集setC,并使用setC中主键id进行回表,获取最终查询结果。

3. Index Merge Sort-Union

Sort-Union索引合并与Union索引合并原理相似,只是比单纯的Union索引合并多了一步对二级索引记录的主键id排序的过程。由OR连接的多个范围查询条件组成的WHERE子句不满足Union算法时,优化器会考虑使用Sort-Union算法。

应用场景约束

1. 总体约束

  • Index Merge不能应用于全文索引(Fulltext Index)。
  • Index Merge只能合并同一个表的索引扫描结果,不能跨表合并。

以上约束适用于Intersection,Union和Sort-Union三种合并类型。此外,Intersection和Union存在特殊的场景约束。

2. Index Merge Intersection

使用Intersection要求AND连接的每个条件必须是如下形式之一:

  • 当索引包含多个列时,每个列都必须被如下等值条件覆盖,不允许出现范围查询。若使用索引为联合索引时,每个列都必须等值匹配,不能出现只匹配部分列的情况。

  • 若过滤条件中存在主键列,主键列可以进行范围匹配。

3. Index Merge Union

使用Union要求OR连接的每个条件,必须是如下形式之一:

  • 当索引包含多个列时,则每个列都必须被如下等值条件覆盖,不允许出现范围查询。若使用索引为联合索引时,在联合索引中的每个列都必须等值匹配,不能出现只匹配部分列的情况。

  • 若过滤条件中存在主键列,主键列可以进行范围匹配。

Index Merge的优缺点

  • Index Merge Intersection在使用到的多个索引上同时进行扫描,并取这些扫描结果的并集作为最终结果集。

  • Index Merge Union在使用到的多个索引上同时进行扫描,并取这些扫描结果的并集作为最终结果集。

  • Index Merge Sort-Union比单纯的Union索引合并多了一步对索引记录的主键id排序的过程。

我们以Index Merge Union为例,对上述分析进行验证。

场景构造

# 创建表
CREATE TABLE T(
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int NOT NULL,
  `b` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`) USING BTREE,
  KEY `idx_b` (`b`) USING BTREE
)ENGINE=InnoDB AUTO_INCREMENT=1;

# 插入数据
DELIMITER $$
CREATE PROCEDURE insertT()
BEGIN
DECLARE i INT DEFAULT 0;
START TRANSACTION;
WHILE i<=100000 do
if (i%100 = 0) then
INSERT INTO T (a, b) VALUES (10,CHAR(rand()*(90-65)+65));
else
INSERT INTO T (a, b) VALUES (i,CHAR(rand()*(90-65)+65));
end if;
SET i=i+1;
END WHILE;
COMMIT;
END$$
DELIMITER ;
call insertT();

# 执行测试语句
SQL1: SELECT * FROM T WHERE a=101 OR b='A';
SQL2: SELECT /*+ NO_INDEX_MERGE(T idx_a,idx_b) */ * FROM T WHERE a=101 OR b='A';
SQL3: SELECT * FROM T WHERE a=10 OR b='A';
SQL4: SELECT /*+ NO_INDEX_MERGE(T idx_a,idx_b) */ * FROM T WHERE a=10 OR b='A';

执行结果及分析

每条语句查询5次,去掉最大值和最小值,取剩余三次结果平均值。4条语句查询结果如下:

测试语句 第一次查询/ms 第二次查询/ms 第三次查询/ms 第四次查询/ms 第五次查询/ms 平均值/ms
SQL1 5.481 5.422 5.117 4.892 5.426 5.322
SQL2 31.129 32.645 30.943 31.142 32.625 31.632
SQL3 7.872 7.200 7.824 7.955 7.949 7.882
SQL4 31.139 33.318 31.476 31.645 31.27 31.464

对比使用索引合并的SQL1和未使用索引合并的SQL2的查询结果可知,使用索引合并的SQL1具有更高的查询效率。

总结

本文介绍了索引合并(Index Merge)包含的三种类型,即交集(intersection)、并集(union)和排序并集(sort-union),以及索引合并的实现原理、场景约束与通过案例验证的优缺点。在实际使用中,当查询条件列较多且无法使用联合索引时,就可以考虑使用索引合并,利用多个索引加速查询。但要注意,索引合并并非在任何场景下均具有较好的效果,需要结合具体的数据分布进行算法的选择。

[点击关注,第一时间了解华为云新鲜技术~]


更多关于HarmonyOS 鸿蒙Next:MySQL中为什么要使用索引合并(Index Merge)?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next:MySQL中为什么要使用索引合并(Index Merge)?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next的上下文中探讨MySQL索引合并(Index Merge)的原因,实际上与操作系统本身无直接关联,但我们可以从数据库优化的角度来解释这一机制。

MySQL中的索引合并是指当查询条件能够利用到多个单列索引时,优化器会选择合并这些索引以生成更高效的执行计划。这种做法的目的在于提高查询性能,尤其是在面对复杂查询时。具体来说,索引合并适用于以下几种情况:

  1. 相交索引合并:当查询条件中的多个列各自有索引,且这些条件在逻辑上是“与”(AND)关系时,MySQL可能会选择使用这些索引来减少扫描的数据量。

  2. 联合索引合并:在某些情况下,即便没有为多个列创建联合索引,MySQL也可能通过合并使用单个列索引来优化查询。

  3. 相同索引的合并:对于同一列上的多个范围条件,如果它们各自有索引,MySQL可能会合并这些索引扫描以减少全表扫描的开销。

索引合并虽然能提升查询效率,但也有其适用场景和限制。例如,当索引过多或查询条件过于复杂时,优化器可能会放弃索引合并策略,转而选择其他执行计划。

如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部