浅析 MySQL 索引
MySQL 索引此博客不是对索引技术的底层进行讲解仅仅讲解初阶知识方便理解索引和了解索引原理不涉及底层与深层次知识之后可能会写在使用 MySQL 的场景下数据库往往存储着海量数据几万条、几百万条甚至上千万条。如果不对数据做任何处理查询时就只能从头到尾逐行遍历全表扫描时间效率极低。 就像一本几千页的书没有目录我们想找到某一页内容只能从头翻到尾。索引的出现很好地解决了这个问题。它本质上是一种数据结构能够帮助数据库在不扫描全部数据的情况下快速定位到目标记录。后面我们将结合原理和实验来深入理解。1. 没有索引会怎样MySQL 的数据最终是持久化存储在磁盘文件中的例如 InnoDB 引擎的独立表空间.ibd文件或系统共享表空间。因此对表进行增删改查本质上都会涉及磁盘 I/O。而磁盘 I/O 的瓶颈在于机械硬盘存在磁头寻道和盘片旋转延迟随机读取效率很低即使使用 SSD其读写速度也与内存相差几个数量级InnoDB 以页默认 16KB为单位读取数据如果目标记录分散在不同页中会产生大量随机 I/O。如果没有索引查询就必须进行全表扫描将磁盘上的数据页逐页加载到内存再逐行比对筛选。对于 800 万量级的表这意味着可能要加载数百 MB 甚至上 GB 的数据。如果此时再叠加高并发磁盘 I/O 和 CPU 资源会被迅速耗尽系统基本丧失可用性。因此索引不是可选项而是大数据量下保证查询性能的必需品。实验预告下文将基于 800 万条测试数据对比有索引和无索引情况下的查询性能差异直观感受索引的作用。-- -- 0. 开启函数创建权限MySQL 8.0 必需只需执行一次 -- SET GLOBAL log_bin_trust_function_creators 1; -- -- 1. 创建 EMP 表根据插入字段推断的表结构 -- DROP TABLE IF EXISTS EMP; CREATE TABLE EMP ( empno INT PRIMARY KEY, ename VARCHAR(255), job VARCHAR(255), mgr INT, hiredate DATE, sal DECIMAL(10,2), comm DECIMAL(10,2), deptno INT ); -- -- 2. 创建随机字符串函数 -- DELIMITER $$ CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) BEGIN DECLARE chars_str VARCHAR(100) DEFAULT abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ; DECLARE return_str VARCHAR(255) DEFAULT ; DECLARE i INT DEFAULT 0; WHILE i n DO SET return_str CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1 RAND() * 52), 1)); SET i i 1; END WHILE; RETURN return_str; END $$ DELIMITER ; -- -- 3. 创建随机数字函数 -- DELIMITER $$ CREATE FUNCTION rand_num() RETURNS INT(5) BEGIN DECLARE i INT DEFAULT 0; SET i FLOOR(10 RAND() * 500); RETURN i; END $$ DELIMITER ; -- -- 4. 创建批量插入存储过程 -- DELIMITER $$ CREATE PROCEDURE insert_emp(IN start INT(10), IN max_num INT(10)) BEGIN DECLARE i INT DEFAULT 0; SET autocommit 0; REPEAT SET i i 1; INSERT INTO EMP VALUES ( (start i), rand_string(6), SALESMAN, 0001, CURDATE(), 2000, 400, rand_num() ); UNTIL i max_num END REPEAT; COMMIT; END $$ DELIMITER ; -- -- 5. 执行存储过程插入 8000000 条记录 -- CALL insert_emp(100001, 8000000);查询未设置索引的列用时 6.95 秒查询构建索引的列用时 10 毫秒以内。可以明确观察到是否构建索引对大数据量的查找造成了数量级的差距如果再叠加并发场景未设置索引基本不可用。2. 除了索引MySQL 还做了哪些努力索引能帮我们快速定位数据但定位之后数据终究要从磁盘读到内存。为了尽可能减少真正的磁盘 I/OMySQLInnoDB 引擎在索引之外还做了以下关键设计InnoDB 以 16KB「页」为单位与磁盘交互InnoDB 管理数据的最小存储单元叫做Page页默认大小为16KB。为什么不是一条一条读而是整页读因为数据在磁盘上通常是连续存储的尤其是主键顺序插入时。一次 I/O 读取 16KB可能就把目标记录附近的相邻数据也加载进来了。这利用了空间局部性原理用一次 I/O 换多次潜在的内存命中。作为对比操作系统文件系统的块Block通常默认是 4KB但 InnoDB 的页大小是独立配置的innodb_page_size默认 16KB 是数据库场景下权衡后的结果。Buffer Pool —— 在内存中缓存数据页磁盘 I/O 和内存操作的速度差了几个数量级。InnoDB 在启动时会向操作系统申请一大块内存叫做Buffer Pool用来缓存从磁盘读来的数据页。读数据先查 Buffer Pool命中就直接返回逻辑 I/O未命中才去磁盘读取真实页物理 I/O。写数据先修改 Buffer Pool 中的页此时这个页就变成了脏页Dirty Page。脏页不会立刻写回磁盘而是由后台线程Page Cleaner在合适的时机批量刷盘。这种延迟写策略把大量随机磁盘写转化成了内存写 批量顺序刷盘极大提升了吞吐量。索引解决的是如何快速找到数据在哪而以上设计解决的是找到之后如何尽可能少读磁盘、少写磁盘。两者结合才构成了 MySQL 在海量数据下依然能高效运转的完整图景。3. 理解索引从页到 B 树前面提到InnoDB 以16KB 的页为单位管理数据。那么当表中有 800 万条记录、分布在成千上万个页中时如何快速找到目标记录答案藏在两个层次页内如何快速定位记录以及页与页之间如何快速定位。3.1 页内Page Directory页目录先回到单个页。一页 16KB可能存储几十到几百条记录。如果页内只能从头到尾扫描就算确定了目标页查找效率依然很低。InnoDB 的解决方案是在每个数据页的尾部维护一个Page Directory页目录也叫槽Slot。它记录了页内部分记录的偏移位置且这些记录是按主键有序的。当需要在页内查找某条记录时MySQL 会先在 Page Directory 中二分查找快速定位到包含目标记录的槽再在该槽对应的小范围内遍历。这样就把页内全表扫描变成了页内二分查找。但这只能解决一个页内部的问题。当数据量增大需要成千上万个页时页与页之间又该如何组织3.2 页间没有索引时只能线性遍历当多个页存储数据时InnoDB 用双向链表将它们按主键顺序连接起来页头中的FIL_PAGE_PREV和FIL_PAGE_NEXT指针。此时如果没有任何索引查询就只能从第一个页开始沿着链表顺序遍历直到找到目标记录。如果有 1000 万条数据分散在几万个页中这种线性遍历的代价依然是不可接受的。能不能像书的目录一样给这些页也建立一个目录呢3.3 给页建立目录B 树的雏形答案是肯定的。MySQL 引入了一种分层目录的结构最底层的页叶子节点存放真实的用户数据上层的页非叶子节点不存数据只存两样东西键值指向子页的指针。具体规则是每个非叶子节点中的目录项存放的是其指向的子页中最小的键值或键值范围。当需要查找某条记录时从根节点出发比较键值确定目标记录应该落在哪个子页沿着指针进入子页如果子页还是非叶子节点重复步骤 1~2直到进入叶子节点在页内通过 Page Directory 定位具体记录。这样每一次比较都能排除掉一整棵子树的数据而不是一条条比对。3.4 最终形态B 树随着数据量增长目录项也会变多。当根节点存不下时就再往上抽一层形成多级索引。最终这棵树就演变成了B 树B 树有几个至关重要的特征决定了它为什么适合数据库索引非叶子节点不存数据只存键值和指针这意味着一个 16KB 的页能存下成百上千个指针而不是只能存几十条数据。树变得非常矮胖。所有真实数据都存放在叶子节点保证了查询的稳定性不管查哪条数据I/O 次数都差不多树的高度次。叶子节点之间用双向链表连接这让范围查询BETWEEN、、极其高效找到左边界后直接顺着链表向后遍历无需回退到上层节点。3.5 一个直观的计算假设一行数据约 500 字节一个 16KB 的叶子页大约能存32 条记录。非叶子节点只存主键假设 INT 占 4 字节和页指针约 6 字节一个 16KB 页大约能存1600 个目录项。那么2 层 B 树1600 × 32 ≈5 万条记录3 层 B 树1600 × 1600 × 32 ≈8000 万条记录这意味着对于 800 万数据的表B 树的高度通常只有3 层。即使目标数据在磁盘上最多也只需要3 次磁盘 I/O就能定位到这和不建索引时的全表扫描可能需要几万次 I/O相比差距是数量级的。3.6 为什么别的数据结构不行链表链表线性遍历无法实现跨越式的筛选最终的时间效率仍然不可观二叉搜索树有退化问题可能退化成线性结构AVL 和 红黑树虽然是平衡或者近似平衡但是毕竟是二叉结构相比较多阶 B意味着树整体过高大家都是自顶向下找层高越低意味着系统与硬盘更少的 IO Page 交互。虽然很优秀但是有更加优秀的选择。Hash官方的索引实现方式中 MySQL 是支持 HASH 的Hash 跟其算法特征决定了虽然有时候也很快 (O(1))不过在面对范围查找就明显不行另外还有其他差别有兴趣可以查一下。最值得比较的是 InnoDB 为何不用 B树 作为底层索引B树B树B树节点既有数据又有 Page 指针而 B 只有叶子节点有数据其他目录页只有键值和 Page 指针。B叶子节点全部相连而 B 树 没有。为何选择 B 树呢两树的本质区别在于 “非叶子节点是否存储data”如果非叶子节点不对 data 进行存储空间就可以存储更多的目录页从而使得树更矮所以IO操作次数更少。并且叶子节点相连更便于进行范围查找。综上所述使用 B 树实现更佳。3.7 小结创建索引本质上就是在构建一棵 B 树针对 InnoDB 的主键索引而言。B 树通过矮胖的结构和页间目录把全表扫描变成了树的高度次 I/O。索引解决的是数据在哪个页的问题而 Page Directory 解决的是数据在页内的哪个位置的问题。两者配合才完成了最终的快速定位。4. 聚簇索引 VS 非聚簇索引MyISAM 引擎同样使用 B 树作为索引结构叶节点的 data 域存放的是数据记录的地址。下图为 MyISAM 表的主索引 Col1 为主键。其中 MyISAM 最大的特点是将索引 Page 和数据 Page 分离也就是叶子节点没有数据只有对应数据的地址。相较于 InnoDB 索引 InnoDB 是将索引和数据放在一起的。InnoDB 这种用户数据与索引数据在一起索引方案叫做聚簇索引。5. 辅助索引与回表MySQL 除了默认会建立主键索引外我们用户也有可能建立按照其他列信息建立的索引一般这种索引可以叫做辅助普通索引。对于 MyISAM ,建立辅助普通索引和主键索引没有差别无非就是主键不能重复而非主键可重复。下图就是基于 MyISAM 的 Col2 建立的索引和主键索引没有差别同样 InnoDB 除了主键索引用户也会建立辅助普通索引我们以上表中的 Col3 建立对应的辅助索引如下图可以看到 InnoDB 的非主键索引中叶子节点并没有数据而只有对应记录的 key 值。所以通过辅助普通索引找到目标记录需要两次索引查找首先检索辅助索引获得主键然后用主键到主索引中检索获得记录。这种过程就叫做回表查询为何 InnoDB 针对这种辅助普通索引的场景不给叶子节点也附上数据呢原因就是太浪费空间了。

相关新闻

《系统分析师教程(第2版)》笔记——第 18 章 移动应用系统分析与设计

《系统分析师教程(第2版)》笔记——第 18 章 移动应用系统分析与设计

第 18 章 移动应用系统分析与设计【版权声明与学习说明】 本文系笔者学习《系统分析师教程(第2版)》第18章后,结合个人理解整理的原创学习笔记。文中所有表格、通俗化举例及箭头式总结,均为本人消化后重新归纳表述,不代…

2026/10/20 18:34:36 阅读更多 →
2026年苏州工业废气治理优选:哪家服务商更值得信赖?

2026年苏州工业废气治理优选:哪家服务商更值得信赖?

随着环保政策的不断收紧,工业企业面临的环保压力也越来越大。如何选择一家可靠且高效的环保服务提供商,成为了众多企业亟待解决的问题。本文将通过具体数据和案例,对比分析几家在苏州地区具有较高知名度的环保服务提供商,帮助您做…

2026/10/20 3:35:26 阅读更多 →
STM32H5_IAP升级项目复盘——从缺陷到改进

STM32H5_IAP升级项目复盘——从缺陷到改进

STM32H5工业互联项目复盘 二、缺陷一:IAP 烧写失败后的"假成功" 2.1 升级流程回顾 2.1.1 整体流程 PC 上位机 主控 STM32H5│ ││ 1. 写寄存器 0 0x55 ││ (MODBUS_PRIVATE_CM…

2026/10/20 17:18:26 阅读更多 →

最新新闻

SSM+Vue教学资源库系统开发实战:从上传审核到在线预览

SSM+Vue教学资源库系统开发实战:从上传审核到在线预览

1. 起因:教学资源乱成一锅粥,才决定动手做这个库先交代一下背景。我们这边是搞创客教育的团队,课程横跨图形化编程、开源硬件、3D建模几个方向,老师和助教加起来十几号人,积累的教案、课件、代码示例、电路图、视频素材…

2026/10/21 1:55:36 阅读更多 →
使用 TypeScript 集成 Azure App Configuration:集中配置、Feature Flags 与动态刷新的完整实战指南

使用 TypeScript 集成 Azure App Configuration:集中配置、Feature Flags 与动态刷新的完整实战指南

AI 技能AI 插件人工智能 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600 agentic skills. Includes CLI, local MCP, c…

2026/10/21 1:55:36 阅读更多 →
戴森球计划工厂蓝图免费仓库:7000+张蓝图放下就能跑

戴森球计划工厂蓝图免费仓库:7000+张蓝图放下就能跑

戴森球计划工厂蓝图免费仓库:7000张蓝图放下就能跑 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints 玩《戴森球计划》,多数人都会卡死在开局那半小时…

2026/10/21 1:55:36 阅读更多 →
如何在未越狱 iPhone 上玩 Windows PC 游戏:Madeira iOS 模拟器完整教程

如何在未越狱 iPhone 上玩 Windows PC 游戏:Madeira iOS 模拟器完整教程

如何在未越狱 iPhone 上玩 Windows PC 游戏:Madeira iOS 模拟器完整教程 【免费下载链接】Madeira Run x86-64 Windows PC games on jailed iOS via FEX-Emu Wine DXMT 项目地址: https://gitcode.com/GitHub_Trending/mad/Madeira Madeira 是一款跑在未越…

2026/10/21 1:55:36 阅读更多 →
wifit3 WPA 握手嗅探:5 个蹲守窗口,几分钟抓下 4-way

wifit3 WPA 握手嗅探:5 个蹲守窗口,几分钟抓下 4-way

wifit3 WPA 握手嗅探:5 个蹲守窗口,几分钟抓下 4-way 【免费下载链接】wifit3 Wifite but USB-only & cross-platform. 项目地址: https://gitcode.com/GitHub_Trending/wi/wifit3 wifit3 是一款 USB 网卡审计工具,WPA 握手嗅探是它的默认常驻状态。蹲一…

2026/10/21 1:55:36 阅读更多 →
Docker网络完全指南:从命名空间、网桥到Overlay跨主机通信

Docker网络完全指南:从命名空间、网桥到Overlay跨主机通信

1. 为什么网络是容器化应用最容易翻车的地方先从一个非常典型的场景说起。某团队开发了一个微服务Demo,容器里跑着前端、后端、数据库三个进程,本地开发时一切正常。结果一到部署环境,前端服务就是连不上后端接口,后端日志里全是连…

2026/10/21 1:54:35 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/20 9:50:45 阅读更多 →