- hello,大家好,我是 Lorin,最近无意中看到一道 MySQL 经典面试题,什么是索引合并,也许有的小伙伴比较疑惑,心里想难道是联合索引?其实并不是,下面我们就来看看什么是索引合并。
什么是索引合并
- 我们在使用 Explain 语句有时候可能会遇到查询类型为:index_merge,正如字面意思所示,这就是我们常说的索引合并。
- 什么是索引合并呢?索引合并优化是一种查询优化技术,它利用多个索引来加速查询的执行。当一个查询中包含多个条件,并且这些条件分别适用于不同的索引时,MySQL 可以将这些索引合并起来使用,减少了回表的次数,以加速查询的执行。
- 仅限合并来自单个表的索引扫描,而不是跨多个表的扫描。
- 如上图所示,将 n 次回表查询合并为一次处理,加速查询的执行,接下来我们看看索引合并的几种具体情况。
准备
- 准备我们需要的数据,并插入10条数据:
- 注:数据量太少会导致优化器选择其它执行计划,大家可以插入1000条左右数据或使用强制索引。
CREATE TABLE `test_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT '',
`merchant_id` bigint(20) NOT NULL,
`area` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_user_id` (`user_id`) USING BTREE,
KEY `idx_merchant_id` (`merchant_id`) USING BTREE,
KEY `idx_area` (`area`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (1, '1', 1, 1);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (2, '2', 2, 2);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (3, '3', 3, 3);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (4, '4', 4, 4);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (5, '5', 5, 5);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (6, '6', 6, 6);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (7, '7', 7, 7);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (8, '8', 8, 8);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (9, '9', 9, 9);
INSERT INTO `test_table` (`user_id`, `name`, `merchant_id`, `area`) VALUES (10, '10', 10, 10);
合并算法
- Index Merge 合并有几种常见算法,显示在输出Extra字段 中EXPLAIN,优化器会根据成本估算选择合适的算法:
交集算法Using intersect(...)
并集算法 Using union(...)
排序并集算法Using sort_union(...)
交集算法
- 使用交集算法有两种场景:
// 1、多个由下列表达式构造的组合(每个索引包含部分)
key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN
EXPLAIN SELECT * FROM test_table WHERE merchant_id = 3 AND area = 3;
// 2、主键范围查询 和 上述表达式组合
EXPLAIN SELECT * FROM test_table WHERE merchant_id = 3 AND id < 3;
并集算法
// 1、多个由下列表达式构造的组合(每个索引包含部分)
key_part1 = const1 OR key_part2 = const2 ... OR key_partN = constN
EXPLAIN SELECT * FROM test_table WHERE merchant_id = 3 AND area = 3;
// 2、主键范围查询 和 上述表达式组合
EXPLAIN SELECT * FROM test_table WHERE merchant_id = 3 OR id < 3;
排序并集算法
- 适用于多个范围查询使用 OR 条件查询。
EXPLAIN select * from test_table where merchant_id < 3 or area<3;
- sort-union 算法和 union 算法之间的区别在于,sort-union 算法必须先获取所有行的行主键ID ,然后在回表之前它们进行排序。
影响索引合并的因素
配置项
- Index Merge 的使用受制于 系统变量的index_merge、 index_merge_intersection、 index_merge_union和 index_merge_sort_unionflags 的值optimizer_switch 。默认情况下,所有这些标志都是on. 要仅启用某些算法,请设置index_merge 为off,并仅启用应允许的其他算法。
优化器
- 优化器会根据成本分析结果选择成本最低的执行计划。比如下列语句在数据量比较少了会选择全表扫描。
EXPLAIN select * from test_table where merchant_id < 3 or area<3;
参考