news 2026/9/9 12:13:40

mysql基础(十一)索引及SQL优化(上)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mysql基础(十一)索引及SQL优化(上)

文章目录

    • 索引介绍:
        • 1. 索引是什么
        • 2. B+Tree
        • 3. 聚簇索引与二级索引
          • 聚簇索引
          • 二级索引
        • 4. 回表与覆盖索引
          • 回表
          • 覆盖索引
        • 5. 索引的创建、查看与删除
    • 索引的设计原则:
    • SQL优化流程:
      • 1. 定位需要优化的SQL
          • 1. SHOW STATUS
          • 2. SHOW PROCESSLIST
          • 3. 慢查询日志
          • 4. Performance Schema
        • 2. EXPLAIN分析执行计划
        • 3. EXPLAIN ANALYZE:估算 vs 实际
        • 4. Performance Schema性能分析
          • 查看耗时较高的SQL
          • sys Schema
        • 5. Profiling性能分析(旧版,已弃用)
        • 6. optimizer_trace分析优化器选择
          • 开启optimizer_trace
          • OPTIMIZER_TRACE主要内容
    • 索引的使用:

索引介绍:

1. 索引是什么

索引是一种用于提高数据查询效率的数据结构。

没有索引时,MySQL 查询数据往往需要:

从第一行开始 ↓ 逐行扫描 ↓ 找到符合条件的数据

这种方式通常称为:

全表扫描

当数据量很大时,全表扫描需要检查大量数据,查询效率会明显下降。

建立索引后,可以通过索引快速缩小查找范围:

查询条件 ↓ 索引 ↓ 快速定位数据范围 ↓ 读取目标记录

对于 MySQL 8 默认的 InnoDB 存储引擎,普通索引和主键索引主要采用:

B+Tree

结构。

表中存在大量数据如果没有索引的时候,要寻找一条数据得进行全表扫描直到找到为上。而有索引的情况下,利用 B+树 的数据结构,只需要查找部分数据即可定位目标。
此外,MySQL也支持其他类型的索引,如用于地理空间数据的 R-树索引、用于内存表的哈希索引,以及用于全文搜索的倒排索引等。
索引有两大优势:
其一检索快——索引相当于书本的目录,提高检索效率的同时降低数据库IO成本。
其二排序方便——用索引排序,降低数据排序成本和CPU消耗。
也有两大劣势:
其一占空间——索引本身也是一张逻辑上的表结构(物理上以B+树存储),需要占用额外的磁盘空间。特别是 InnoDB 的二级索引,其叶子节点存储的是索引列的值 + 主键值,在查询时需要回表获取完整记录,这既是索引的空间成本,也可能带来一定的查询开销。
其二更新慢——当执行 DML 操作时,InnoDB 不仅需要维护聚簇索引(即数据本身),还需要同步更新该表上的所有二级索引。每多一个索引,就多一棵 B+树需要维护,这会显著降低 INSERT、UPDATE、DELETE 的执行速度。

索引大致分三大类:单值——一个索引只包含单个列,唯一——索引列的值必须唯一(主键约束和唯一约束就属于此类)并允许有空值,复合索引——一个索引包含多个列。

需要注意:

索引并不是另一张独立的数据表,而是数据库为了提高数据访问效率而维护的一种数据结构。


2. B+Tree

InnoDB 的 B+Tree 索引具有以下特点:

非叶子节点 → 主要保存索引键和指向下一层节点的指针 叶子节点 → 保存真正需要的数据或主键信息 叶子节点之间 → 按顺序形成链表

B+Tree 相比普通二叉树更适合数据库索引,主要原因是:

树的高度较低 ↓ 一次节点可以保存更多索引项 ↓ 查询时需要访问的页面更少 ↓ 减少磁盘I/O

同时,叶子节点按照索引顺序排列,因此非常适合:

范围查询 排序 最左前缀查询
3. 聚簇索引与二级索引

InnoDB 的索引可以重点理解为:

聚簇索引 二级索引
聚簇索引

InnoDB 通常使用主键作为聚簇索引。

聚簇索引 B+Tree 的叶子节点保存:

完整的一行数据

可以简单理解:

主键 ↓ B+Tree ↓ 叶子节点 ↓ 完整行记录

因此根据主键查询:

SELECT*FROMuserWHEREid=100;

通常可以直接通过聚簇索引找到完整数据。

二级索引

普通索引、唯一索引、联合索引等非聚簇索引,通常都属于二级索引。

二级索引的叶子节点一般保存:

索引列值 + 主键值

例如:

KEYidx_name(name)

对应的二级索引可以理解为:

name + id

如果查询:

SELECT*FROMuserWHEREname='张三';

MySQL 可能先通过:

idx_name

找到:

主键id

然后再根据主键访问聚簇索引,读取完整记录。

这个过程称为:

回表

4. 回表与覆盖索引
回表

例如存在:

KEYidx_name(name)

查询:

SELECT*FROMuserWHEREname='张三';

执行过程可能是:

二级索引 idx_name ↓ 找到 name='张三' ↓ 得到对应主键id ↓ 根据id查询聚簇索引 ↓ 读取完整行数据

其中:

二级索引 → 聚簇索引

这个过程就是:

回表
覆盖索引

如果查询需要的字段全部都可以从索引中取得,就不需要再次访问聚簇索引。

例如:

SELECTname,idFROMuserWHEREname='张三';

如果存在:

KEYidx_name(name)

由于 InnoDB 二级索引的叶子节点中通常已经包含:

name + 主键id

因此查询结果可以直接从二级索引得到:

二级索引 ↓ 直接返回数据 ↓ 无需回表

这种情况称为:

覆盖索引

EXPLAIN中经常可以看到:

Using index

表示查询可以利用覆盖索引取得所需数据。

Using index不代表“只有一个索引”或者“必须是等值查询”,它主要表示查询所需要的列能够直接从索引中取得。


5. 索引的创建、查看与删除

下面继续使用原文中的实际操作截图和案例。

常见创建方式:

CREATEINDEXidx_nameONuser(name);

创建唯一索引:

CREATEUNIQUEINDEXuk_nameONuser(name);

创建联合索引:

CREATEINDEXidx_name_ageONuser(name,age);

查看索引:

SHOWINDEXFROMuser;

删除索引:

DROPINDEXidx_nameONuser;

也可以通过:

ALTERTABLE

添加索引。

索引案例:




索引的设计原则:

索引并不是越多越好。

索引能够提高查询效率,但同时也会带来:

占用磁盘空间 ↓ INSERT需要维护索引 UPDATE可能需要维护索引 DELETE需要维护索引

因此应该根据实际查询场景合理设计。主要原则:
1.查多量大——查询频率高且数据量较大。
2.最佳条件——索引字段就当从where子句条件中选择,如果有多组条件,选择最常用且过滤效果最好的。
3.唯一索引——使用唯一索引,区分度越高效率也越高。
4.控制数量——索引不是越多越好,索引越多维护代价也越高,会带来降低DML效率且占据空间的负面效果。
5.短索引——索引也占空间,所以索引字段长度尽量简短。
6.最左前缀——由多个字段组成的联合索引本质是一棵复合 B+Tree,使用中依情况使用最前面几个(最左边),不能跳过字段。
7.很少修改——做为索引的字段应当很少进行DML操作。

SQL优化流程:

1. 定位需要优化的SQL

常用方式包括:

SHOW STATUS SHOW PROCESSLIST 慢查询日志 Performance Schema
1. SHOW STATUS

可以查看 MySQL 各类 SQL 的执行情况,例如:

2. SHOW PROCESSLIST

可以查看当前正在执行的连接和SQL,定位低效SQL语句:


也可以:

SHOWFULLPROCESSLIST;

重点关注:

运行时间很长 状态异常 长期未结束

的 SQL。

3. 慢查询日志

慢查询日志用于记录:

执行时间超过阈值的SQL

是生产环境定位慢 SQL 的重要方式之一。

4. Performance Schema

Performance Schema 可以从整个 MySQL 运行情况中统计:

哪些SQL执行次数最多 哪些SQL累计耗时最高 哪些SQL平均耗时较高 哪些SQL扫描行数异常

后面会单独介绍。

2. EXPLAIN分析执行计划

找到需要优化的 SQL 后,可以使用:

EXPLAINSELECT...

查看 MySQL 优化器为 SQL 生成的执行计划。

EXPLAIN主要帮助我们判断:

表的访问顺序 ↓ 访问方式 ↓ 可能使用哪些索引 ↓ 最终使用哪个索引 ↓ 预计检查多少行 ↓ 是否需要额外过滤、排序、临时表

分析时通常重点关注:

type possible_keys key key_len rows filtered Extra

常用字段:

字段主要含义
id查询块标识
select_type查询类型
table当前访问的表
partitions实际访问的分区
type表访问方式
possible_keys可能使用的索引
key优化器最终选择的索引
key_len实际使用的索引长度
ref与索引进行比较的列、常量或表达式
rows优化器估算需要检查的行数
filtered预计经过条件过滤后剩余数据的百分比
Extra额外的执行信息




需要注意:

普通EXPLAIN展示的是优化器生成的估算执行计划,并不代表 SQL 真正执行后的实际耗时。

分析执行计划演示:




接下来通过对执行情况表的字段做演示说明:

id字段:


select_type(查询类型)字段:








3. EXPLAIN ANALYZE:估算 vs 实际

普通:

EXPLAIN

主要回答:

MySQL准备怎么执行?

从 MySQL 8.0.18 开始,还可以使用:

EXPLAINANALYZESELECT...

它会真正执行 SQL,然后同时显示:

优化器估算 + 真实执行情况

例如:

EXPLAINANALYZESELECT*FROMuserWHEREname='张三';

结果中重点关注:

cost rows actual time actual rows loops

简单理解:

信息含义
cost优化器估算成本
rows优化器估算行数
actual time实际执行时间
actual rows实际返回行数
loops当前执行节点实际循环次数

例如:

估算 rows = 10 实际 rows = 100000

说明:

优化器估算 和 真实数据分布

可能存在较大偏差。

这时可以进一步排查:

统计信息是否准确 索引基数是否合理 数据分布是否严重倾斜 执行计划是否选择合理

必要时可以:

ANALYZETABLE表名;

更新统计信息。

可以简单记忆:

EXPLAIN → MySQL准备怎么执行? EXPLAIN ANALYZE → MySQL真正执行后怎么样?

注意:EXPLAIN ANALYZE会真正执行 SQL,因此对于高成本 SQL,尤其在生产环境中,使用前需要先评估影响。


4. Performance Schema性能分析

Performance Schema 是 MySQL 内置的性能监控体系。

它可以持续收集:

SQL执行 线程 等待事件 锁 I/O 事务 Stage

等运行信息。

查看是否启用:

SHOWVARIABLESLIKE'performance_schema';

MySQL 8 中一般为:

ON
查看耗时较高的SQL

Performance Schema 会将结构相同、参数不同的 SQL 进行归一化统计。

例如:

SELECT*FROMuserWHEREid=1;SELECT*FROMuserWHEREid=2;SELECT*FROMuserWHEREid=100;

会归一化为类似:

SELECT*FROMuserWHEREid=?

这种归一化后的 SQL 称为:

Statement Digest

可以查询:

SELECTSCHEMA_NAME,DIGEST_TEXT,COUNT_STAR,ROUND(SUM_TIMER_WAIT/1000000000000,3)AStotal_seconds,ROUND(AVG_TIMER_WAIT/1000000000000,6)ASavg_seconds,SUM_ROWS_EXAMINED,SUM_ROWS_SENTFROMperformance_schema.events_statements_summary_by_digestWHERESCHEMA_NAMEISNOTNULLORDERBYSUM_TIMER_WAITDESCLIMIT10;

重点字段:

字段含义
DIGEST_TEXT归一化后的SQL
COUNT_STAR执行次数
SUM_TIMER_WAIT累计执行时间
AVG_TIMER_WAIT平均执行时间
SUM_ROWS_EXAMINED累计检查行数
SUM_ROWS_SENT累计返回行数

适合找:

执行次数特别高的SQL 累计耗时特别高的SQL 平均耗时较高的SQL 扫描行数明显过多的SQL
sys Schema

MySQL 还提供:

sys

Schema。

它主要是在 Performance Schema 的基础上提供更加容易阅读的视图。

例如:

SELECTquery,db,exec_count,total_latency,avg_latency,rows_examined,rows_sentFROMsys.statement_analysisORDERBYtotal_latencyDESCLIMIT10;

可以直接看到:

SQL 执行次数 累计耗时 平均耗时 扫描行数 返回行数

可以简单理解:

Performance Schema → 底层、全面 sys Schema → 对Performance Schema进一步封装,使用更加方便

Performance Schema 与 EXPLAIN 的关系:

Performance Schema ↓ 从整个系统中找到问题SQL ↓ EXPLAIN ↓ 分析这条SQL的执行计划

5. Profiling性能分析(旧版,已弃用)

注意:SHOW PROFILESHOW PROFILES已经被 MySQL 官方标记为弃用,未来版本可能移除。现代 MySQL 更推荐使用 Performance Schema 进行性能分析。

本节保留 Profiling 的实际操作案例,主要用于理解旧版本 MySQL 对一条 SQL 各个执行阶段耗时的分析方法。






6. optimizer_trace分析优化器选择

EXPLAIN可以告诉我们:

优化器最终选择了什么执行计划

但有时候还需要继续回答:

明明有索引,为什么没有使用? 存在多个索引,为什么选择了这个? 优化器比较过哪些执行路径? 为什么放弃另外一个索引?

这时可以使用:

optimizer_trace

查看优化器生成执行计划时的决策过程。

简单理解:

EXPLAIN → 最终选了什么 optimizer_trace → 为什么这么选
开启optimizer_trace

在当前 Session 中执行:

SEToptimizer_trace='enabled=on';


然后执行需要分析的 SQL,再查看:

SELECT*FROMinformation_schema.OPTIMIZER_TRACE;


分析结束后关闭:

SEToptimizer_trace='enabled=off';
OPTIMIZER_TRACE主要内容

结果中的:

TRACE

是一段 JSON 数据。

典型结构可以大致理解为:

join_preparation ↓ 查询准备、SQL改写 join_optimization ↓ 条件处理、索引分析、成本计算、执行计划选择 join_execution ↓ 执行阶段相关信息

其中:

join_optimization

通常最值得关注。

索引的使用:




版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 12:12:24

ROS2服务通信C++实战:从AddTwoInts到自定义接口

先说个真实感受:很多刚接触ROS2的朋友,上来就把话题通信玩得飞起,但一碰到“客户端发个请求、服务端回个结果”这种一问一答的需求,就开始发懵。我在帮几个项目做技术评审时,见过不少人用话题硬模拟请求响应&#xff0…

作者头像 李华
网站建设 2026/9/9 12:12:10

diagram-design:可编程、可验证、可集成的可视化系统工程

1. “diagram-design”不是画图,是构建可演进的视觉化系统“diagram-design”这个词组在搜索引擎里被拆解成两个高频词:diagram(图表、示意图、结构图)和 design(设计、架构、编排)。但如果你真把它当成“用…

作者头像 李华
网站建设 2026/9/9 12:11:04

生成式搜索与AI反问:内容生态的权力反转与优化策略

生成式搜索带来的不只是“答案变长了”,而是整个内容生态的权力关系在悄悄反转。过去我们习惯向搜索引擎提问,然后从十条蓝色链接里挑一个点进去;现在AI直接给你一段综合答案,甚至会在信息不足时反问一句:“你具体指哪…

作者头像 李华
网站建设 2026/9/9 12:06:16

水稻微生物组互作机制:从根际招募到免疫调控

在朋友圈刷到 iMeta 讲坛第 25 期的预告,看到谢卡斌老师要讲水稻与微生物组互作机制,时间定在 1 月 29 号晚上 7 点。说实话,我第一反应是"这个题目终于有人系统地讲了"。这几年国产测序平台和宏基因组分析流程越来越成熟&#xff…

作者头像 李华
网站建设 2026/9/9 12:05:21

从零实现STM32F103 A/B OTA升级:Bootloader分区设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 12:04:53

工业级智能硬件系统骨架设计:五颗关键芯片协同实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华