MYSQL:关于索引你想知道的

一、基础概念

索引是数据库中对一列或多列值进行排序的数据结构。其主要作用是加快数据检索速度,相当于书本的目录。本质是存储引擎层面的实现,不同存储引擎索引实现不同。

1. 索引的本质

  • 数据结构:本质上是特殊的查找数据结构,最常见的是B+树结构。
  • 存储位置:独立于表数据之外的额外存储结构。
  • 实现层面:由存储引擎实现而非服务器层,不同引擎实现方式不同。

2. 核心作用原理

  • 加速查询:通过减少全表扫描,将O(n)复杂度降至O(log n)。
  • 排序优化:对ORDER BY操作避免filesort临时表排序。
  • 连接效率:提高表连接操作的匹配速度。

3. 关键特性

  • 选择性:索引列不同值的数量与总行数的比值(Cardinality)。
  • 覆盖索引:查询列都包含在索引中时,无需回表查数据。
  • 最左前缀:复合索引使用时必须从最左列开始匹配。

4. 存储结构对比

存储引擎 默认索引类型 特性
InnoDB B+Tree 支持事务、行锁、聚集索引
MyISAM B+Tree 表锁、非聚集索引
Memory Hash 内存表、极速查询

二、索引类型

  • B-Tree索引:最常见的索引类型,适用于全键值、键值范围或键前缀查找。
  • 哈希索引:基于哈希表实现,只支持等值比较查询。
  • 全文索引:用于文本内容的搜索。
  • 空间索引:用于地理空间数据类型。

1. B-Tree索引(B+树索引)

实现方式:

css 复制代码
基于B+树数据结构实现。
InnoDB存储引擎的默认索引类型。

特点:

复制代码
所有值按顺序存储。
每个叶子节点到根节点的距离相同。
适合全键值、键值范围或键前缀查找。

适用场景:

scss 复制代码
精确匹配(=, IN)。
范围查询(>, <, BETWEEN)。
前缀匹配(LIKE 'abc%')。
排序(ORDER BY)。

限制:

css 复制代码
必须按最左前缀查找。
不能跳过索引中的列。
如果查询中有范围查询,B+树的有序性被范围查询打断,后面的列无法继续使用索引。

2. 哈希索引

实现方式:

复制代码
基于哈希表实现。
Memory引擎默认索引类型。
InnoDB中并非传统意义的哈希索引,主键或唯一键的等值查询。

特点:

less 复制代码
只支持等值比较查询(=, <=>)。
查询速度非常快(O(1)时间复杂度)。
不存储字段值,只存储哈希值和行指针。
InnoDB自动为"热点"B+Tree索引页构建内存哈希索引,完全自动管理,无需用户干预。

优点:

复制代码
适合精确查询,性能极高。

缺点:

复制代码
不支持排序。
不支持范围查询。
不支持部分索引列查询。
存在哈希冲突可能。

与传统哈希索引的区别:

特性 InnoDB自适应哈希索引 传统哈希索引
存储位置 内存中 磁盘/内存
管理方式 自动 手动创建
持久性 非持久(重启消失) 可持久化
范围查询 不支持 不支持
等值查询 极快 极快

3. 全文索引(Full-text)

实现方式:

perl 复制代码
InnoDB和MyISAM都支持。InnoDB从MySQL 5.6开始支持,具备事务特性。
使用倒排索引(inverted index)存储单词及其位置信息。

特点:

scss 复制代码
专门用于文本内容的搜索。 
可以对CHAR、VARCHAR和TEXT列创建。
支持自然语言搜索和布尔搜索。

工作原理:

scss 复制代码
分词机制:按空格/标点分割单词;移除停用词(the, and等常见词);存储词干(部分语言支持)。
相关性计算:基于TF-IDF(词频-逆文档频率)算法;考虑词在文档中的出现频率;考虑词在全集中的稀有程度。

使用方式(sql):

sql 复制代码
-- 创建全文索引
ALTER TABLE articles ADD FULLTEXT(title, body);
-- 使用全文索引搜索
SELECT * FROM articles WHERE MATCH(title, body) AGAINST('MySQL索引' IN NATURAL LANGUAGE MODE);

4. 空间索引(Spatial)

实现方式:

scss 复制代码
R-Tree数据结构。
MyISAM和InnoDB(MySQL 5.7+)支持。

特点:

scss 复制代码
用于地理空间数据类型(GEOMETRY, POINT, LINESTRING, POLYGON等)。
支持空间关系函数计算(ST_Contains, ST_Distance等)。

使用示例(sql):

sql 复制代码
-- 创建空间索引
CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g));
-- 空间查询
SELECT * FROM geom WHERE ST_Contains(g, Point(1,1));

5. 复合索引(多列索引)

特点:

css 复制代码
在多个列上建立的索引,构建B+树结构。
遵循最左前缀原则。查找时相当于使用"a_b_c"这样的组合键进行匹配
列顺序非常重要。如INDEX(a,b,c)会先按a排序,a相同按b排序,b相同再按c排序。

使用建议:

复制代码
将选择性高的列放在前面。
考虑查询的常用条件顺序。
避免创建过多复合索引。

6. 覆盖索引

特点:

复制代码
查询只需要通过索引就能获取所需数据。
不需要回表查询数据行。
可以显著提高查询性能。

使用示例(sql):

sql 复制代码
-- 如果索引包含(col1, col2)
SELECT col1, col2 FROM table WHERE col1 = 'value';  -- 覆盖索引
SELECT * FROM table WHERE col1 = 'value';  -- 不是覆盖索引

每种索引类型都有其适用的场景,在实际应用中应该根据查询模式和数据特点选择合适的索引类型。对于大多数OLTP应用,B-Tree索引是最常用的选择;全文索引适合文本搜索场景;空间索引则专用于地理空间数据处理。

三、索引优缺点

1. 索引的核心优势

1.1 查询加速机制

  • 数据结构优化:B+树索引将查询复杂度从O(n)降至O(log n),通过树形结构快速定位数据。
  • 减少IO操作:索引体积通常远小于表数据,加载更少数据页到内存(如3层B+树可支撑千万级数据)。
  • 预排序特性:索引本身有序,对ORDER BY/GROUP BY操作避免临时表排序(Extra显示"Using index")
  • 示例场景:10万行数据的用户表,无索引的name查询需扫描全表,建立索引后仅需3-4次IO即可定位。 1.2 锁与并发优化
  • 行锁升级:InnoDB通过索引实现行锁,无索引会退化为表锁(如UPDATE未走索引将锁全表)
  • MVCC支持:索引帮助多版本控制快速定位可见版本,提升并发读性能 1.3 覆盖索引特性 当查询列都包含在索引中时,引擎可直接从索引获取数据,避免回表操作。如: -- 有索引(a,b) SELECT a,b FROM table WHERE a=1 -- 完全通过索引完成

2. 索引的性能代价

2.1 写入开销放大

  • B+树维护成本:每次INSERT需更新索引树(页分裂概率约5-10%),导致写入速度下降30-50%。
  • 日志膨胀:InnoDB需记录索引变更到redo log,增加IO压力。
  • 性能影响:表添加5个索引后,写入TPS可能从2000降至1200。 2.2 存储空间占用
  • 典型占用比例:索引空间通常达数据量的20-30%,复合索引列越多空间增长越快
  • 内存压力:BP缓冲池需缓存索引页,可能挤占数据页空间 2.3 优化器误判风险
  • 统计信息滞后:当数据分布变化但统计信息未更新时(如20%数据突变),可能选择错误索引。
  • 索引合并代价:优化器选择合并多个单列索引时,性能可能不如预期。

3. 底层数据结构影响

3.1 B+树索引特性

  • 平衡写入与查询: 相比B树,B+树通过非叶子节点仅存键值的设计,实现:更高扇出(通常500+子节点);更稳定的查询性能(任何查询路径长度相同);
  • 范围查询优化: 叶子节点链表结构特别适合范围扫描 3.2 哈希索引局限
  • 内存依赖:自适应哈希索引仅内存有效,重启后需重新构建。
  • 精确匹配限定:仅支持=、IN操作,无法用于排序或范围查询。

四、使用实践

  • 选择区分度高的列建索引。
  • 避免对频繁更新的列建索引。
  • 考虑索引列的数据类型大小。
  • 多列索引遵循最左前缀原则。

1. 使用事项

1.1 创建原则:

sql 复制代码
常用于WHERE、JOIN、ORDER BY的列。
高选择性的列优先,选择性阈值:Cardinality/总行数 > 10% 的列适合建索引。
避免过度索引(一般表不超过5-6个)。

1.2 使用限制:

ini 复制代码
索引列不能参与计算(如WHERE col+1=5)。
字符串前缀索引长度需要合理设置。
注意NULL值对索引使用的影响。

2. 性能影响

2.1 正向影响:

css 复制代码
读操作性能提升10-100倍。
降低服务器CPU消耗。
减少磁盘I/O压力。

2.2 负面影响:

erlang 复制代码
写操作需要维护索引结构数据。
占用额外存储空间(约增加20-30%)。
索引碎片化需要定期维护。

理解这些基本概念是进行有效索引优化的重要基础,实际应用中需要结合具体查询模式和数据特征进行索引设计和调整。

3. 最左前缀原则

3.1 基本规则:

复制代码
查询必须从索引最左边的列开始使用
不能跳过中间的列直接使用后面的列

3.2 有效使用示例:

css 复制代码
-- 索引:INDEX(a,b,c)
-- 有效使用(使用a):
WHERE a = 1 
-- 有效使用(使用a,b)
WHERE a = 1 AND b = 2
-- 有效使用(使用a,b,c)
WHERE a = 1 AND b = 2 AND c = 3

3.3 无效使用示例:

css 复制代码
-- 无效(未使用a)
WHERE b = 2
-- 无效(跳过了b)
WHERE a = 1 AND c = 3

3.4 范围查询的影响

关键规则:

sql 复制代码
范围查询(>, <, BETWEEN, LIKE等)会使后面的索引列失效
范围查询列自身仍能使用索引

示例分析:

css 复制代码
-- 索引:INDEX(a,b,c)
-- 仅a,b能用索引(c失效)
WHERE a = 1 AND b > 2 AND c = 3
-- 仅a能用索引(b,c失效)
WHERE a > 1 AND b = 2 AND c = 3

理解复合索引的使用逻辑需要结合B+树的结构特点,合理设计复合索引可以显著提升查询性能,但也需要避免过度索引导致的写性能下降和维护成本增加。

4. 其它

4.1 监控指标

  • 索引使用情况监控,查找无用索引
sql 复制代码
SELECT * FROM sys.schema_unused_indexes;
  • 索引效率分析,查看Cardinality(不重复值的预估数量,比值越趋近0时索引效果越差)
sql 复制代码
SHOW INDEX FROM table_name;
  • Cardinality:
sql 复制代码
不重复值的预估数量。选择性公式:Cardinality/表总行数,比值趋近0时索引效果差

4.2 特殊场景优化

  • 前缀索引:对长字符串使用INDEX(column(10))指定前缀长度

  • 函数索引:MySQL 8.0+支持INDEX((UPPER(column)))表达式索引 4.3 排序与分组优化

  • ORDER BY优化:

    当排序顺序与索引顺序一致时,可避免filesort,同样遵循最左前缀原则。

  • GROUP BY优化:

    分组操作也可以利用复合索引,需要满足最左前缀且中间无间隔。

作者:飞蓬

相关推荐
tan180°6 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
DuelCode7 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社27 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
why技术7 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理7 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
ai小鬼头8 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github
简佐义的博客8 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
爬山算法8 小时前
MySQL(116)如何监控负载均衡状态?
数据库·mysql·负载均衡
Code blocks9 小时前
使用Jenkins完成springboot项目快速更新
java·运维·spring boot·后端·jenkins