MySQL 基础:索引的定义与作用

一、索引的定义与核心作用

1. 定义

索引是 MySQL 中用于优化查询效率的数据结构,类比书籍的"目录",无需遍历全表即可快速定位数据位置。

2. 核心作用

提升查询速度:避免全表扫描(Full Table Scan),减少磁盘 I/O 和 CPU 资源消耗;

优化排序/分组:支持 GROUP BY ORDER BY 操作快速完成(无需额外排序);

加速表连接:优化 JOIN 操作中关联字段的匹配效率。

二、索引的工作逻辑

当执行 SELECT 查询时,MySQL 执行流程如下:

  1. 解析查询语句,识别查询的表和字段;

  2. 检查该字段是否存在索引:

    若有索引:遍历索引表(数据结构如 B+ 树),快速定位到数据记录行的物理地址,直接读取数据;

    若无索引:执行全表扫描,逐行遍历表中所有数据,匹配目标结果(效率低、资源消耗高)。

三、索引的副作用(不可忽视)

索引并非"越多越好",存在以下代价:

  1. 占用额外磁盘空间:索引表独立于数据表格,会消耗磁盘存储(如大表的组合索引可能占用大量空间);

  2. 增加更新开销:修改(INSERT/UPDATE/DELETE)含索引的表时,需同步更新对应的索引表(如修改主键值时,主键索引需重新排序);

  3. 不合理索引降低效率:如在低选择性字段创建索引,可能导致 MySQL 放弃使用索引,直接全表扫描。

四、索引的创建依据(适合/不适合场景)

1. 适合创建索引的场景

主键和外键:默认创建主键索引,外键常用于表连接,必须建索引;

大数据量表:记录数超过 300 行的表,全表扫描代价过高;

高频查询字段:WHERE 子句中频繁出现的字段(如用户查询、筛选条件);

连接/排序/分组字段:JOIN 关联字段、GROUP BY/ORDER BY 操作的字段;

高选择性字段:字段不同值占比高(如身份证号、手机号,选择性接近 1),索引过滤效果好;

小字段:优先在 INT、VARCHAR(短) 等小字段建索引(长文本、BLOB 等大字段索引开销极高)。

2. 不适合创建索引的场景

低选择性字段:如性别(男/女)、布尔值(0/1),索引过滤效果差,不如全表扫描;

更新频繁的字段:如订单状态(高频更新),索引同步开销会抵消查询收益;

小表(<300 行):全表扫描速度快,索引带来的开销大于收益;

高频全表查询字段:若查询常使用 SELECT * 且无过滤条件,索引无效。

五、MySQL 常见索引类型及特点

索引类型 核心特点 适用场景
主键索引(PRIMARY KEY) 唯一、非空,一张表仅一个,默认自动创建,底层为聚簇索引(数据与索引存储在一起) 表的唯一标识(如用户 ID、订单 ID)
唯一索引(UNIQUE KEY) 字段值唯一(允许 NULL 值,仅一个 NULL),避免重复数据 用户名、邮箱等需唯一约束的字段
组合索引(复合索引) 基于多个字段创建(如 idx_name_age (name, age)),遵循"最左前缀原则" 多字段联合查询(如 WHERE name='xxx' AND age=xx
全文索引(FULLTEXT) 支持长文本模糊匹配(如文章内容、评论),不支持精确查询 博客、新闻等文本内容的关键词搜索

补充:组合索引"最左前缀原则"

示例:创建组合索引 idx_a_b_c (a, b, c),仅支持以下查询场景命中索引:

  • WHERE a=?(左前缀匹配)

  • WHERE a=? AND b=?(连续前缀匹配)

  • WHERE a=? AND b=? AND c=?(全匹配)

不命中场景:WHERE b=? WHERE a=? AND c=?(跳过中间字段)。

六、索引与慢查询的关联

1. 慢查询与索引的关系

慢查询定义:默认情况下,执行时间超过 2 秒的 SELECT 语句(可通过 long_query_time 配置修改);

核心原因之一:查询未使用索引(全表扫描),导致耗时过长;

配置日志记录:在 /etc/my.cnf 中开启以下配置,记录未使用索引的慢查询:

TOML 复制代码
[mysqld]
slow_query_log = 1  # 开启慢查询日志
slow_query_log_file = /var/lib/mysql/mysql-slow.log  # 日志存储路径
long_query_time = 2  # 慢查询阈值(单位:秒)
log_queries_not_using_indexes = 1  # 记录未使用索引的 SQL

配置后需重启 MySQL 服务生效。

2. 验证索引有效性:EXPLAIN 工具

作用:分析 SQL 执行计划,查看是否使用索引、索引类型、扫描行数等;

用法:在查询语句前加 EXPLAIN,示例:

SQL 复制代码
EXPLAIN SELECT * FROM user WHERE id=1;

关键字段解读:

  • type:索引使用类型(ALL 表示全表扫描,ref/range/eq_ref 表示使用索引);

  • key:实际使用的索引名称(NULL 表示未使用索引);

  • rows:预估扫描的行数(值越小,效率越高)。

七、索引底层与优化技巧

1. 索引底层数据结构(MySQL 默认)

采用 B+ 树 结构,优势:

叶子节点有序排列,支持范围查询(如 BETWEEN IN);

叶子节点存储数据地址(非聚簇索引)或数据本身(聚簇索引),查询效率稳定;

树高度低(百万级数据仅需 3-4 层),磁盘 I/O 次数少。

2. 聚簇索引 vs 非聚簇索引

聚簇索引:索引与数据存储在一起(如主键索引),查询无需"回表",效率最高;

非聚簇索引:索引与数据分离,叶子节点存储主键值,查询需通过主键值二次查找数据(回表),效率略低。

3. 索引失效的常见场景(避坑!)

索引字段使用函数/运算:WHERE SUBSTR(name,1,2)='张'(无法命中 name 索引);

模糊查询以 % 开头:WHERE name LIKE '%三'(全模糊 %三% 也失效);

OR 条件中部分字段无索引:WHERE id=1 OR age=20(若 age 无索引,整个查询可能全表扫描);

隐式类型转换:WHERE phone='123456'phone 为 INT 类型,字符串与数字转换导致索引失效);

联合查询中违背最左前缀原则(见组合索引部分)。

4. 索引优化技巧

覆盖索引:查询字段仅包含索引列(如 SELECT id, name FROM user WHERE id=1id 为主键索引),避免回表;

定期维护索引:删除冗余索引(如已存在 idx_a_b,无需再建 idx_a)、优化碎片索引(OPTIMIZE TABLE 表名);

避免过度索引:一张表索引数量建议不超过 5 个,过多索引会导致更新变慢。

八、核心小结

  1. 索引核心价值:加速查询,减少全表扫描开销;

  2. 创建原则:"高频查询、高选择性、小字段"优先,避开"更新频繁、低选择性"字段;

  3. 验证工具:用 EXPLAIN 检测索引是否生效,结合慢查询日志优化索引;

  4. 平衡取舍:索引并非越多越好,需权衡查询效率与更新开销。

相关推荐
繁星星繁2 小时前
【Mysql】数据库基础
android·数据库·mysql
心动啊1212 小时前
简单学下chromaDB
开发语言·数据库·python
妮妮喔妮2 小时前
redis热点key拆分和读多副本
数据库·redis·缓存
雪球不会消失了2 小时前
MySQL(开发篇)
数据库·mysql·oracle
qq_348231852 小时前
Redis 事务(MULTI/EXEC)与 Lua 脚本的核心区别
数据库·redis·lua
whn19773 小时前
寻找listener.log
数据库
代码游侠3 小时前
学习笔记——文件I/O
linux·数据库·笔记·学习·算法
Tanjia_kiki3 小时前
无法打开新数据库 ‘test‘。CREATE DATABASE 中止。 (Microsoft SQL Server,错误: 9004)
数据库