当前位置: 首页 > article >正文

中间件专栏之MySQL篇——MySQL的索引原理

MySQL的索引是MySQL这个体系中很重要的一环,并且它的概念很多人理解的都有偏差,因此本文对其做一个梳理。

一、索引是什么

首先,索引是数据库表中的一种数据结构,用于加速查询。索引类似于书籍的目录,可以快速找到所需的数据,提高查询效率。表面上索引就是用户自己选择和设置的一个或多个字段,但实际在创建索引时,MySQL会为我们创建一棵b+树(默认情况,也有其他存储结构),用于存储我们创建的索引。

二、索引的作用

加快查询速度:减少数据扫描,提高 SELECT 语句性能。
提高排序效率:支持 ORDER BY 更快排序。
优化 WHERE 语句:快速找到匹配的数据行。
缺点

  • 占用存储空间
  • 插入、更新、删除操作变慢(需要维护索引)。

通俗来讲,如果我们只创建了数据表但没有创建索引,能查询到我们指定的语句吗?可以,但是通过全表扫描得到的结果,如果数据多则非常耗时,而如果我们创建了索引,则直接去该索引的b+树查询,查询效率得到提高。 

 三、索引的分类

1. 按功能分类

索引类型作用SQL 语句
普通索引 (INDEX)加速查询CREATE INDEX idx_name ON users(name);
唯一索引 (UNIQUE INDEX)确保列值唯一CREATE UNIQUE INDEX idx_email ON users(email);
主键索引 (PRIMARY KEY)作为表的唯一标识ALTER TABLE users ADD PRIMARY KEY (id);
全文索引 (FULLTEXT INDEX)支持全文搜索CREATE FULLTEXT INDEX idx_content ON articles(content);

2. 按存储结构分类

索引类型存储结构特点
B-Tree 索引平衡树结构默认索引类型,适用于大多数查询
Hash 索引哈希映射适用于等值查询(如 =),不支持范围查询
Full-Text 索引倒排索引用于文本搜索
R-Tree 索引空间索引适用于 GIS(地理信息系统)数据

3. 按字段数分类

索引类型特点SQL 语句
单列索引针对单个字段CREATE INDEX idx_name ON users(name);
多列索引 (组合索引)针对多个字段,提高复合查询效率CREATE INDEX idx_name_age ON users(name, age);

4. 按索引创建方式分类

索引类型作用SQL 语句
自动索引主键会自动创建索引PRIMARY KEY(id)
手动索引手动添加索引CREATE INDEX idx_name ON users(name);
隐式索引唯一键会自动创建索引UNIQUE(email)

还有很重要的索引是聚簇索引和辅助索引 ,这两种索引属于 存储结构分类,具体来说:

索引类型分类特点
聚簇索引 (Clustered Index)存储结构索引- 数据和索引存储在同一个结构中,按照索引顺序存储数据。
- 每张表只能有一个聚簇索引,通常是主键索引
- Innodb 引擎默认使用聚簇索引。
辅助索引 (Secondary Index)存储结构索引- 也称 非聚簇索引,索引存储的是指向主键的指针
- 可以有多个辅助索引。
- 需要通过主键索引回表查询获取完整数据(回表查询会影响性能)。

四、索引的存储结构

如前面提到的,每一个索引对应一棵b+树。

为什么使用b+树数据结构?b+树是多叉树,可以降低层高,减少磁盘io的访问数(redis是红黑树,是二叉树),并且b+树的叶子节点依次相连,方便范围查询。

b+树的特征:1、非叶子节点只存储索引信息;2、叶子节点还存储数据信息;3、叶子节点之间依次相连;4、节点大小为16kb,映射的是连续的磁盘页。

五、索引优化与索引失效

1.1 使用合适的索引

索引类型适用场景示例 SQL
主键索引 (PRIMARY KEY)唯一标识记录,查询高效ALTER TABLE users ADD PRIMARY KEY (id);
唯一索引 (UNIQUE INDEX)需要保证字段唯一性,如邮箱CREATE UNIQUE INDEX idx_email ON users(email);
普通索引 (INDEX)提高查询速度CREATE INDEX idx_name ON users(name);
组合索引 (Composite Index)适用于多字段查询CREATE INDEX idx_name_age ON users(name, age);
全文索引 (FULLTEXT INDEX)适用于文本搜索CREATE FULLTEXT INDEX idx_content ON articles(content);

优化建议

  • 优先使用主键索引和唯一索引,它们查询效率最高。
  • WHERE 条件涉及多个字段时,考虑组合索引,避免多个单列索引带来的回表查询。
  • LIKE 查询尽量使用全文索引,提高匹配速度。

1.2 覆盖索引(Covering Index)

定义:如果索引已经包含查询所需的所有字段,就可以直接从索引中返回数据,而不需要回表查询,提高性能。

优化示例

CREATE INDEX idx_name_email ON users(name, email);
SELECT name, email FROM users WHERE name = '张三';
  • idx_name_email 包含 nameemail,查询时直接从索引中获取数据,无需回表,查询更快

1.3 最左前缀匹配

规则组合索引 查询时,必须按照索引字段的从左到右顺序使用,否则索引可能失效。

优化示例

CREATE INDEX idx_name_age ON users(name, age);
SELECT * FROM users WHERE name = '张三';  -- ✅ 能用索引
SELECT * FROM users WHERE name = '张三' AND age = 30;  -- ✅ 能用索引
SELECT * FROM users WHERE age = 30;  -- ❌ 索引失效(未使用最左前缀)

*1.4 避免 SELECT ,只查询需要的列

优化示例

SELECT name, email FROM users WHERE name = '张三';

不推荐

SELECT * FROM users WHERE name = '张三';  -- 可能导致不必要的回表查询

 2. 索引失效的常见原因

可参考下图

六、bufferpool 的设计、空闲页与脏页的管

理策略、刷盘时机

MySQL 中 Buffer Pool 的设计及管理策略

在 MySQL InnoDB 存储引擎中,Buffer Pool(缓冲池)是用于缓存数据页、索引页的核心组件,能大幅提高数据库的性能。下文将详细介绍 Buffer Pool 的设计、空闲页与脏页的管理策略、以及刷盘时机


1. Buffer Pool 的设计

Buffer Pool 是 InnoDB 的内存缓存区,主要作用是减少磁盘 I/O 操作,加速查询性能。其结构如下:

  • 数据页缓存:缓存表的数据页,减少磁盘读取。
  • 索引页缓存:缓存 B+ 树索引,提高查询速度。
  • Undo 页缓存:用于事务回滚和 MVCC 版本管理。
  • Adaptive Hash Index(AHI):自适应哈希索引,提高查询效率。
  • Flush List:存储脏页信息,决定刷盘策略。

Buffer Pool 结构

Buffer Pool 由多个 Page(页) 组成,每个页的大小通常是 16KB(可配置为 8KB 或 4KB)。当查询数据时,InnoDB 先从 Buffer Pool 查找,若未命中,则从磁盘读取,并可能淘汰旧数据。


2. 空闲页与脏页的管理策略

2.1 页面分类

页面类型描述
Free Pages(空闲页)还未使用或被释放的页,可直接用于存放新数据。
Clean Pages(干净页)仅用于缓存磁盘数据,与磁盘数据一致。
Dirty Pages(脏页)被修改但尚未写回磁盘的数据页。

2.2 页面管理策略

InnoDB 采用 LRU(最近最少使用)+ young/old 子列表 机制:

  1. 新加载的页 先放入 LRU 列表的 middle 部分(old 列表),而非头部。
  2. 访问次数多的页 被移动到 young 列表,减少被淘汰的概率。
  3. 当 Buffer Pool 需要空间时,优先淘汰 old 列表的页(避免新加载的数据瞬间淘汰旧数据)。

此外,LRU 机制还会结合 Adaptive Flushing 进行优化,防止 Buffer Pool 被高频访问的数据填满。


3. 刷盘时机

脏页必须写回磁盘(即刷盘)以保证数据一致性,InnoDB 采用以下几种刷盘策略:

3.1 被动刷盘(Lazy Write)

  • 当 Buffer Pool 空间不足,需要淘汰旧数据时,会将脏页写入磁盘。
  • 触发条件:
    • innodb_max_dirty_pages_pct 限制脏页比例。
    • innodb_lru_scan_depth 影响 LRU 淘汰深度。

3.2 主动刷盘

刷盘时机触发原因说明
Checkpoint(检查点刷盘)防止重启时数据丢失InnoDB 定期执行,保证 redo log 覆盖范围内的脏页已落盘。
Redo Log 写满Redo Log Buffer 满了刷新部分脏页,以保证日志可复用。
事务提交刷盘(flush at commit)innodb_flush_log_at_trx_commit=1事务提交后,立即刷盘,提高数据安全性(但影响性能)。
后台线程刷盘Master Thread 定期执行后台线程周期性刷盘,保证脏页不会过多积累。

3.3 刷盘方式

MySQL 提供以下几种刷盘策略(通过 innodb_flush_log_at_trx_commit 参数控制):

参数值刷盘策略适用场景
0事务提交时不刷盘,靠后台刷盘适用于高性能但数据可能丢失的场景。
1(默认)事务提交时写入 redo log 并同步磁盘最安全,保证数据一致性。
2事务提交时写入 redo log,但不立即同步磁盘适用于高并发,部分数据丢失可接受的情况。


 


http://www.kler.cn/a/570125.html

相关文章:

  • 【架构】信息系统战略规划的三阶段演进及核心方法
  • 通过多线程同时获取H264和H265码流
  • scala基础学习-匹配模式
  • Kettle 最常见的性能优化面试题
  • 计算机网络——因特网和互联网
  • 【AI论文】MedVLM-R1:通过强化学习激励视觉语言模型(VLMs)的医疗推理能力
  • 鸿蒙5.0实战案例:基于hvigor插件定制构建
  • 深入探索像ChatGPT这样的大语言模型-01-Base Model-Pretraining阶段
  • ArcGIS Pro应用指南:如何为栅格图精确添加坐标信息
  • 拓扑排序_走多远
  • SQL Server下载和安装细节
  • 4.Linux操作系统命令
  • Microk8s Ingress实现七层负载均衡
  • 玩转ChatGPT:Claude 3.7 Sonnet进行数据分析(分类)
  • 如何评估大语言模型(LLMs)
  • LLM - Attention Is All You Need 的理解
  • C++ 二叉树代码
  • SQL 中为什么参数多了not in 比 in 慢多了,怎么优化
  • Linux常见操作命令
  • AI 赋能 RPA:一键生成热点话题文章的奥秘