🚀图文并茂解读 MySQL 联合索引底层存储结构及索引查找过程

前言

  • 大家好,我是 Lorin ,联合索引(Composite Index)又称复合索引,它包括两个或更多列。与单列索引不同,联合索引可以覆盖多个列,这有助于加速复杂查询和过滤条件的检索。联合索引的列顺序非常重要,因为查询优化器会按照索引列的顺序执行搜索。
  • 本文将从联合索引基本概念、底层存储结构、索引查找过程、实践建议几个方面图文并茂进行详细介绍。

版本

sql 复制代码
SELECT VERSION();

5.7.36-log

数据准备

SQL

sql 复制代码
// 创建表
CREATE TABLE `test_table_union_index` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `merchant_id` int(20) NOT NULL,
  `order_id` int(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `merchant_id_order_id_union_index` (`merchant_id`,`order_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

// 插入数据
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (3, 1);
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (3, 2);
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (4, 3);
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (4, 3);
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (5, 1);
INSERT INTO `test_table_union_index` (`merchant_id`, `order_id`) VALUES (5, 2);

// 查询 SQL EXPLAIN 分析
EXPLAIN SELECT * FROM test_table_union_index WHERE merchant_id = 3 AND order_id = 2;

数据创建结果

  • SQL 执行完成后,我们可以看到数据库存储了如下数据:

有无联合索引执行情况

sql 复制代码
// 查询 SQL EXPLAIN 分析
EXPLAIN SELECT * FROM test_table_union_index WHERE merchant_id = 3 AND order_id = 2;

无联合索引

存在联合索引

底层存储结构

  • 上图是联合索引 "merchant_id_order_id_union_index" 的底层存储结构(不一定和 MySQL 数据库底层实现完全一致),我们可以看到除了具有单列索引的特点外,联合索引还具有以下一些特点:
sql 复制代码
- B+树通过索引首列值构建,如 merchant_id_order_id_union_index 根据 merchant_id 构建。
- 叶子节点拥有联合索引中的所有字段以及主键字段,且叶子节点数据局部有序,如我们有一个三个字段的联合索引(a,b,c):
叶子节点(1):
a,b,c(1,3,3)
a,b,c(1,3,4)
a,b,c(1,4,1)
a,b,c(1,4,2)

叶子节点(2)
a,b,c(2,3,3)
a,b,c(2,3,4)
a,b,c(2,4,1)
a,b,c(2,4,2)

a 列在B+树整体有序,a 列相同的情况下 b 列数据按序排列,但 c列不一定有序。

查询过程

最左匹配原则

  • 联合索引遵循最左匹配原则,只能从左往右依次搜索联合索引字段,否则索引不生效。
css 复制代码
例如索引是 key_index (a,b,c)。 可以支持 a 、a,b 、a,b,c 3种组合进行查找,但不支持 b,c 、c 进行查找。

查询过程解析

sql 复制代码
SELECT * FROM test_table_union_index WHERE merchant_id = 3 AND order_id = 2;
  • 联合索引遵循最左匹配原则,以上述查询 SQL 为例,联合索引先根据 merchant_id = 3 在构建的B+树索引上进行查询数据,找到叶子节点:
  • 然后根据 order_id = 2 查询定位数据,查询到数据对应的主键 ID = 2,最后进行回表查询。

联合索引优势

支持复杂查询

  • 联合索引能够加速包含多个条件和多个列的查询。这对于联接多个表或需要在多列上进行过滤的查询非常有用。

索引覆盖查询

  • 联合索引可以覆盖多个查询中的列,从而减少了数据库的I/O负载。这意味着数据库不必访问数据行,而可以直接使用索引来满足查询条件。

提高排序和分组性能

  • 如果你的查询需要排序或分组结果,联合索引可以在这方面提供显著的性能改进,特别是当排序或分组涉及索引中的列时。

减少索引数量

  • 使用联合索引可以减少索引的数量,这对于大型数据库来说是一个重要考虑因素,因为每个额外的索引都会增加数据库维护的开销。

使用建议

联合索引的列顺序十分重要

  • 确定哪些列应包括在联合索引中,以及它们的顺序非常重要。通常将最频繁用于过滤条件的列放在索引前面。

建议能使用联合索引尽量使用联合索引

  • 应该尽可能使用联合索引,但联合索引无法满足需求时可以结合单列索引使用。

常见问题分析

为什么遵循最左匹配原则

  • 从联合索引的底层存储结构我们可以知道,联合索引是根据字段从左往右组织的,不从左边的字段开始查询无法使用索引。

联合索引中字段范围查询为什么会导致后续联合索引字段可不用

  • 从联合索引的底层存储结构我们可以知道,叶子节点数据局部有序,下面的案例可以清楚饿展示这个问题:
ini 复制代码
假设存在如下数据:
1(b=1,c=4,d = 10)
2(b=2,c=5,d = 6)
3(b=2,c=5,d = 7)
4(b=3,c=1,d = 2)
5(b=3,c=5,d = 1)

查询条件: b > 1 且 c = 5 , d = 6

先查找 b > 1 :
2(b=2,c=5,d = 6)
3(b=2,c=5,d = 7)
4(b=3,c=1,d = 2)
5(b=3,c=5,d = 1)

再查找 c = 5 , 此时 c 并不是有序的,因此无法使用联合索引字段 c:
2(b=2,c=5,d = 6)
3(b=2,c=5,d = 7)
5(b=3,c=5,d = 1)

综上所述:联合查询中范围查询会导致后续字段数据无序,导致联合索引中后续索引字段失效。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

相关推荐
Cloud云卷云舒13 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
爱笑的源码基地13 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
IT_陈寒14 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学14 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈14 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端
Conan在掘金15 小时前
鸿蒙报错速查:arkts-strict-typing Property does not exist on type 'object',object 装函数就炸,根因 + 真解法
后端
颜酱15 小时前
01 | 骨架搭建:FastAPI + Vue 跑通第一个 SSE 流式问答
前端·人工智能·后端
程序员cxuan16 小时前
Grok Build 被众人唾骂,结果老马把它开源了
人工智能·后端·程序员
莫逸风16 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
从零开始的代码生活_16 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法