MySQL InnoDB 存储引擎的索引详解

在 MySQL 中,InnoDB 是最常用的存储引擎,它支持事务、行级锁和外键约束等功能,而索引则是提升数据库查询性能的关键。在 InnoDB 存储引擎中,索引不仅仅是提高查询速度的工具,还是数据库的核心组成部分之一。本文将详细介绍 InnoDB 存储引擎的索引结构、索引种类、索引优化技巧以及索引失效等方面的知识。

1. InnoDB 索引的结构

在 InnoDB 存储引擎中,索引主要分为两种类型:聚集索引(Clustered Index)非聚集索引(Non-clustered Index)

1.1 聚集索引(Clustered Index)
  • 聚集索引的叶子节点存储的是数据行本身。换句话说,数据行的实际数据存储在索引结构中,索引的顺序就是数据的物理存储顺序。
  • 每个表只能有一个聚集索引,通常是主键索引。
  • 聚集索引通过将表的数据按索引顺序存储,从而提高了对主键字段查询的效率。
1.2 非聚集索引(Non-clustered Index)
  • 非聚集索引的叶子节点并不存储数据行本身,而是存储数据行的指针(通常是聚集索引的主键值)。因此,查询时需要通过指针再次访问数据行。
  • 一个表可以有多个非聚集索引。
1.3 InnoDB 索引的 B+ 树结构

InnoDB 存储引擎中的聚集索引和非聚集索引通常都是基于 B+ 树(自平衡的树状数据结构)来实现的。B+ 树有以下特点:

  • 平衡性:所有叶子节点都位于同一层,因此查询的时间复杂度是 O(log N)。
  • 有序性:叶子节点之间按照大小顺序排列,可以进行范围查询。
  • 高效的插入和删除操作:通过自平衡机制,插入和删除操作能保持树的平衡。

2. InnoDB 索引的类别

InnoDB 支持以下几种类型的索引:

2.1 主键索引(Primary Key Index)
  • 主键索引是一种特殊的聚集索引,用来确保表中每一行的唯一性。InnoDB 表默认使用主键作为聚集索引。
  • 如果没有显式定义主键,InnoDB 会自动选定一个唯一索引作为主键。
2.2 唯一索引(Unique Index)
  • 唯一索引保证索引列的值是唯一的,但允许 NULL 值存在(多个 NULL 值也被视为不同的值)。
  • 唯一索引可以用于加速查询。
2.3 普通索引(Index)
  • 普通索引是最常见的索引类型,它没有唯一性约束,仅用于提高查询效率。
  • 可以用于加速查询,但不保证数据唯一性。
2.4 全文索引(Fulltext Index)
  • 全文索引是专门用于对文本字段进行全文检索的索引类型。通常用于查找包含某个关键词的文本数据。
  • 只适用于 CHARVARCHARTEXT 类型的列。
2.5 空间索引(Spatial Index)
  • 空间索引主要用于对空间数据类型(如 GEOMETRY)进行查询优化。它使用的是 R 树(Region Tree)而不是 B+ 树。

3. 索引的最左前缀原则

InnoDB 索引遵循 最左前缀原则。也就是说,当你使用复合索引(由多个列组成的索引)时,索引的查询可以使用到最左侧的一部分索引。

举个例子:

假设有一个复合索引 (a, b, c),那么查询时,可以利用以下的前缀索引:

  • (a):只使用列 a,是有效的。
  • (a, b):使用列 a 和列 b,是有效的。
  • (a, b, c):使用列 abc,是有效的。

但如果你只使用 (b)(c) 作为查询条件,MySQL 将无法使用这个复合索引,因为它没有按照最左前缀的顺序来查询。


4. 索引覆盖(Covering Index)

索引覆盖是指查询中涉及到的所有列都包含在索引中,从而避免了对表数据的访问。换句话说,查询的数据完全通过索引获取,无需回表操作。

举个例子:

假设有一个复合索引 (a, b, c),并且你执行了如下查询:

SELECT a, b FROM table WHERE a = 1;

如果索引 (a, b, c) 已经包含了查询所需的列 ab,那么 MySQL 可以直接从索引中获取数据,而不需要回到表中去查询。

索引覆盖的好处是能显著提高查询性能,尤其是在大数据量的表中。

5. 索引下推(Index Condition Pushdown,ICP)

索引下推是一种优化技术,它能够将查询条件推送到存储引擎的索引扫描阶段,而不是等到读取数据行时再进行过滤。这样可以减少需要读取的数据行数量,提升查询效率。

  • 在执行查询时,MySQL 会尽可能地将条件应用到索引扫描的阶段,而不是仅仅依赖于后续的行级过滤。

例如,

SELECT * FROM Employees WHERE age > 30 AND salary like '%5000'

其中联合索引(age、salary);

没有索引下推时,执行这条语句的流程:

  • 1、存储引擎使用联合索引查出age>30的二级索引数据(叶子节点中有age、salary、主键);

  • 2、拿到主键回表,到聚簇索引中拿到完整记录;

  • 3、将所有的完整记录返回到server层(服务器层),再进行salary的模糊查询。

开启索引下推后,执行流程:

  • 1、存储引擎使用联合索引查出age>30的二级索引数据(叶子节点中有age、salary、主键);

  • 2、直接在二级索引数据中对salary进行模糊查询。

可以看出索引下推之后减少了回表的次数,从而降低了查询的时间。

6. 索引合并(Index Merge)

索引合并是 MySQL 在某些情况下使用的一个优化技术。当查询条件涉及多个索引时,MySQL 会尝试将多个索引的结果合并起来,从而加快查询速度。

举个例子:

假设有两个索引:idx_aidx_b,查询条件是:

SELECT * FROM table WHERE a = 1 OR b = 2;

MySQL 可以使用索引合并策略,首先分别从 idx_aidx_b 中找到符合条件的记录,然后将它们合并,最后返回结果。

7. 索引失效的情况

索引并不是总能在所有情况下发挥作用。在以下情况下,索引可能会失效:

7.1 使用了不等于操作符(!=<>
SELECT * FROM table WHERE a != 1;

索引无法有效利用,因为不等于操作会导致扫描整个数据集。

7.2 使用了 OR 连接多个条件
SELECT * FROM table WHERE a = 1 OR b = 2;

当查询条件中包含多个列的 OR 时,索引可能无法有效地优化查询,尤其是当 OR 连接的列没有单独建立索引时。

7.3 使用函数
SELECT * FROM table WHERE YEAR(date_column) = 2023;

在where语句中使用函数(如 YEAR())会导致索引失效,因为索引是基于列值进行查找的,函数的使用会改变查询模式。

7.4 LIKE 前缀不匹配

SELECT * FROM table WHERE name LIKE '%abc';

如果 LIKE 查询以通配符 % 开头,索引通常无法被使用,因为 MySQL 无法利用前缀进行快速查找。

8. 如何查看索引

可以通过以下方式查看 MySQL 表的索引信息:

SHOW INDEX FROM table_name;

该语句将列出表 table_name 中所有的索引,包括索引的名称、类型、涉及的列等信息。

也可以使用explain关键字查看一条SQL的执行计划:

EXPLAIN SELECT * FROM users WHERE age > 30;

结果如下:

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEusersrangeidx_ageidx_age4NULL2Using where

这个执行计划的解释为:

  • id: 查询的唯一标识。这里的 1 表示这是一个简单查询。
  • select_type: 查询的类型。SIMPLE 表示这是一个简单的查询(没有子查询)。
  • table: 表名。这里查询的是 users 表。
  • type: 这里的 range 表示 MySQL 使用了范围扫描(age > 30 是一个范围条件),这是比 ALL 更高效的扫描类型。
  • possible_keys: MySQL 能够使用的索引。这里没有索引可用(NULL)。
  • key: 使用了 idx_age 索引,意味着查询能够利用索引进行更高效的检索。
  • key_len: 使用的索引的长度。
  • ref: 如果使用了索引,它将显示与哪个列比较。
  • rows: 预估扫描了 2 行,MySQL 使用了索引来减少扫描的行数。
  • Extra: 附加信息。Using where 表示在扫描每一行时,MySQL 使用了 WHERE 子句的条件进行过滤。

9. 索引优化建议

  1. 选择合适的索引类型:根据查询的特点选择合适的索引类型。如果查询需要精确匹配,可以选择唯一索引;如果查询涉及文本搜索,可以选择全文索引。
  2. 避免过度索引:索引虽然提高查询效率,但会增加写操作的开销。需要在查询性能和写操作性能之间做出平衡。
  3. 创建复合索引:对于多个列的查询,可以考虑创建复合索引,而不是对每个单独列都创建索引。
  4. 避免索引失效的情况:尽量避免在查询中使用 LIKEOR!= 等会导致索引失效的操作。
  5. 定期分析和优化索引:通过 EXPLAIN 语句来分析查询的执行计划,检查索引的使用情况,并根据结果调整索引设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/896070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的RabbitMQ延时队列技术实现

文章目录 基于Spring Boot的RabbitMQ延时队列技术实现延时队列应用场景基本概念实现延时队列添加依赖基础配置配置类设计消息生产者消息消费者 两种TTL设置方式 订单超时关闭实例订单服务消息处理 延迟消息插件安装插件配置延迟交换机 基于Spring Boot的RabbitMQ延时队列技术实…

毕业项目推荐:基于yolov8/yolov5/yolo11的番茄成熟度检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

【智能客服】ChatGPT大模型话术优化落地方案

本文原创作者:姚瑞南 AI-agent 大模型运营专家,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。(转载需经授权) 目录 一、项目背景 1.1 行业背景 1.2 业务现…

STM32的HAL库开发---单通道ADC采集(DMA读取)实验

一、实验简介 正常单通道ADC采集顺序是先开启ADC采集&#xff0c;然后等待ADC转换完成&#xff0c;也就是判断EOC位置1&#xff0c;然后再读取数据寄存器的值。 如果配置了DMA功能&#xff0c;在EOC位被硬件置1后&#xff0c;自动产生DMA请求&#xff0c;然后DMA进行数据搬运…

编译原理基础(1)

1.什么是ASCII码&#xff1f; ASCII码即美国信息交换标准代码&#xff0c;是基于拉丁字母的电脑编码系统&#xff0c;用于显示现代英语和部分西欧语言。其7位编码范围0-127&#xff0c;8位扩展到0-255。字符集含控制字符&#xff08;0-31、127&#xff0c;用于控制设备或表示通…

基于 Highcharts 实现 Vue 中的答题统计柱状图组件

在现代 Web 开发中&#xff0c;数据可视化是一个重要的组成部分&#xff0c;而 Highcharts 是一个广泛使用的 JavaScript 图表库&#xff0c;可以帮助开发者在 Web 页面上轻松地绘制丰富的图表。在本文中&#xff0c;我们将基于 Highcharts 创建一个用于答题统计的柱状图&#…

SQLAlchemyError: A transaction is already begun on this Session.

资料 sqlalchemy 事务 - 简书 在 SQLAlchemy 中&#xff0c;事务是通过会话来管理的。当你开始一个事务&#xff08;例如使用 async with db.begin()&#xff09;&#xff0c;它会开启一个新的事务&#xff0c;并在事务块结束时自动提交或回滚。如果在同一个会话中&#xff0c…

Java Web开发实战与项目——Spring Boot与Redis实现缓存管理

缓存技术在现代Web开发中至关重要&#xff0c;尤其是在高并发的环境中&#xff0c;缓存能够有效减少数据库访问压力、提高系统性能。Redis作为最流行的内存数据存储系统之一&#xff0c;常用于缓存管理。本节将讲解如何在Spring Boot项目中集成Redis&#xff0c;实现缓存管理&a…

C语言学习【1】C语言关于寄存器的封装

目录 1.封装寄存的C语言的语法volatile&#xff1a;unsigned int:*pGpiobOdrvolatile unsigned int * 2.进一步C语言的封装 在嵌入式中&#xff0c;底层一定是操作寄存器&#xff0c;我有一个理念&#xff0c;凡事一定要想清楚&#xff0c;把任何知识点融入自己的理解之中&…

#渗透测试#批量漏洞挖掘#畅捷通T+远程命令执行漏洞

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 一、漏洞概况 二、攻击特征 三、应急处置…

ollama 学习笔记

1. 参考博客&#xff1a;1. Ollama完整教程&#xff1a;本地LLM管理、WebUI对话、Python/Java客户端API应用&#xff1a;https://blog.csdn.net/python122_/article/details/1409457202. https://gitee.com/ai-big-model/ollama/tree/main --》REST APIollama 离线安装包 ollam…

ARM Linux平台下 OpenCV Camera 实验

一、硬件原理 1. OV2640 1.1 基本功能 OV2640 是一款低功耗、高性能的图像传感器&#xff0c;支持以下功能&#xff1a; 最高分辨率&#xff1a;200 万像素&#xff08;1600x1200&#xff09;。 输出格式&#xff1a;JPEG、YUV、RGB。 内置图像处理功能&#xff1a;自动曝…

vue2.x中父组件通过props向子组件传递数据详细解读

1. 父组件向子组件传递数据的步骤 在子组件中定义 props&#xff1a; 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式&#xff08;简单声明&#xff09;或对象形式&#xff08;支持类型检查和默认值&#xff09;。 在父组件中使用子组件时绑定 props&#x…

【Gin】2:快速上手Gin框架(模版、cookie、session)

本文目录 一、模版渲染二、自定义模版函数三、cookie四、Session五、cookie、session区别六、会话攻击 一、模版渲染 在 Gin 框架中&#xff0c;模板主要用于动态生成 HTML 页面&#xff0c;结合 Go 语言的模板引擎功能&#xff0c;实现数据与视图的分离。 模板渲染是一种动态…

【AI绘画】大卫• 霍克尼风格——自然的魔法(一丹一世界)

大卫• 霍克尼&#xff0c;很喜欢这个老头&#xff0c;“艺术是一场战斗”。老先生零九年有了iphone&#xff0c;开始用iphone画画&#xff0c;一零年开始用ipad画画&#xff0c;用指头划拉&#xff0c;据说五分钟就能画一幅&#xff0c;每天早上随手画几幅送给身边的朋友。很c…

解码 NLP:从萌芽到蓬勃的技术蜕变之旅

内容概况&#xff1a; 主要讲述NLP专栏的内容和NLP的发展及其在现代生活中的广泛应用。专栏强调实践为主、理论为辅的学习方法&#xff0c;并通过多个生活场景展示了NLP技术的实际应用&#xff0c;如对话机器人、搜索引擎、翻译软件、电商推荐和智能客服等。 这边我就不多做自我…

解决DeepSeek服务器繁忙问题的实用指南

目录 简述 1. 关于服务器繁忙 1.1 服务器负载与资源限制 1.2 会话管理与连接机制 1.3 客户端配置与网络问题 2. 关于DeepSeek服务的备用选项 2.1 纳米AI搜索 2.2 硅基流动 2.3 秘塔AI搜索 2.4 字节跳动火山引擎 2.5 百度云千帆 2.6 英伟达NIM 2.7 Groq 2.8 Firew…

前端(AJAX)学习笔记(CLASS 2):图书管理案例以及图片上传

* BootStrap弹框 功能&#xff1a;不离开当前页面&#xff0c;显示单独内容&#xff0c;供用户操作 步骤&#xff1a; 1、引入bootstrap.css和bootstrap.js 2、准备弹框标签&#xff0c;确认结构 3、通过自定义属性&#xff0c;控制弹框的显示和隐藏 其中的bootstrap.css…

数据结构:双链表list

list 是 C 标准库中的双向链表容器。 list初始化示例&#xff1a; #include <list>int n 7;std::list<int> lst; // 初始化一个空的双向链表 lststd::list<int> lst(n); // 初始化一个大小为 n 的链表 lst&#xff0c;链表中的值默认都为 0std::list<i…

AI Agent Service Toolkit:一站式大模型智能体开发套件

项目简介 该工具包基于LangGraph、FastAPI和Streamlit构建,提供了构建和运行大模型Agent的最小原子能力,包含LangGraph代理、FastAPI服务、用于与服务交互的客户端以及一个使用客户端提供聊天界面的Streamlit应用。用户可以利用该工具包提供的模板快速搭建基于LangGraph框架…