面试必问系列:MySQL 索引合并优化及底层原理

2023-11-23 21:06:33 浏览数 (3)

  • hello,大家好,我是 Lorin,最近无意中看到一道 MySQL 经典面试题,什么是索引合并,也许有的小伙伴比较疑惑,心里想难道是联合索引?其实并不是,下面我们就来看看什么是索引合并。

什么是索引合并

  • 我们在使用 Explain 语句有时候可能会遇到查询类型为:index_merge,正如字面意思所示,这就是我们常说的索引合并。
  • 什么是索引合并呢?索引合并优化是一种查询优化技术,它利用多个索引来加速查询的执行。当一个查询中包含多个条件,并且这些条件分别适用于不同的索引时,MySQL 可以将这些索引合并起来使用,减少了回表的次数,以加速查询的执行。
  • 仅限合并来自单个表的索引扫描,而不是跨多个表的扫描。
是否使用索引合并对比是否使用索引合并对比
  • 如上图所示,将 n 次回表查询合并为一次处理,加速查询的执行,接下来我们看看索引合并的几种具体情况。

准备

  • 准备我们需要的数据,并插入10条数据:
  • 注:数据量太少会导致优化器选择其它执行计划,大家可以插入1000条左右数据或使用强制索引。
代码语言:sql复制
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(...)

交集算法

  • 使用交集算法有两种场景:
代码语言:sql复制
// 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;

并集算法

代码语言:sql复制
// 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 条件查询。(因此不要再说 OR 条件无法使用索引,而是 OR 条件前后存在无索引的列会导致索引失效)
  • index merge union 的使用前提是主键有序,当辅助索引获取列对应主键值无序时,先对获取的主键进行排序,然后进行合并。
merge sort union过程merge sort union过程
代码语言:sql复制
EXPLAIN select * from test_table where merchant_id < 3 or area<3;

EXPLAIN select * from test_table where merchant_id < 3 or area=3;

影响索引合并的因素

配置项

  • Index Merge 的使用受制于系统变量的index_merge、 index_merge_intersection、 index_merge_union和 index_merge_sort_union flags 的值optimizer_switch 。默认情况下,所有这些标志都是on. 要仅启用某些算法,请设置index_merge 为off,并启用允许的算法。
  • 配置项查看:
代码语言:sql复制
SHOW VARIABLES LIKE 'optimizer_switch';

优化器

  • 优化器会根据成本分析结果选择成本最低的执行计划。比如下列语句在数据量比较少了会选择全表扫描。
代码语言:sql复制
EXPLAIN select * from test_table where merchant_id < 3 or area<3;

参考

  • https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html

个人简介

0 人点赞