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优化:

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

作者:飞蓬

相关推荐
Piper蛋窝25 分钟前
Go 1.19 相比 Go 1.18 有哪些值得注意的改动?
后端
码农BookSea31 分钟前
不用Mockito写单元测试?你可能在浪费一半时间
后端·单元测试
codingandsleeping2 小时前
Express入门
javascript·后端·node.js
ss2732 小时前
基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
spring boot·后端·高考
郭不耐2 小时前
PostgreSQL与MySQL哪个适合做时空数据分析?
mysql·postgresql·数据分析
专注API从业者3 小时前
《Go 语言高并发爬虫开发:淘宝商品 API 实时采集与 ETL 数据处理管道》
开发语言·后端·爬虫·golang
Asthenia04123 小时前
Netty writeAndFlush与Pipeline深入分析
后端
欧先生^_^3 小时前
Scala语法基础
开发语言·后端·scala
YH.4 小时前
MySQL 主从复制
mysql
GetcharZp4 小时前
xterm.js 终端神器到底有多强?用了才知道!
前端·后端·go