浅析 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/7/21 16:41:43 阅读更多 →
2026年苏州工业废气治理优选:哪家服务商更值得信赖?

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

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

2026/7/23 4:10:53 阅读更多 →
STM32H5_IAP升级项目复盘——从缺陷到改进

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

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

2026/7/22 21:48:23 阅读更多 →

最新新闻

OpenClaw持久记忆机制与动态上下文管理解析

OpenClaw持久记忆机制与动态上下文管理解析

1. OpenClaw的持久记忆机制解析OpenClaw采用文件系统存储记忆的设计理念,通过纯Markdown文件实现记忆的持久化存储。这种设计有三大核心优势:首先,所有记忆内容对用户完全透明可查看;其次,文件系统天然的版本控制特性便…

2026/7/24 6:44:12 阅读更多 →
静矩和形心

静矩和形心

第1节 静矩和形心

2026/7/24 6:44:12 阅读更多 →
TVP5160模拟视频解码芯片实战:Y/C分离、3DNR降噪与SCART覆盖详解

TVP5160模拟视频解码芯片实战:Y/C分离、3DNR降噪与SCART覆盖详解

1. 项目概述与核心价值如果你在十几年前做过模拟视频信号处理相关的项目,比如DVD录像机、电视卡或者视频采集盒,那么TI的TVP5160这颗芯片大概率在你的BOM清单里出现过。它不像现在主流的HDMI或MIPI接口芯片那样“时髦”,但在那个标清模拟视频…

2026/7/24 6:44:12 阅读更多 →
2026年大模型技术突破与智能体开发实践

2026年大模型技术突破与智能体开发实践

1. 2026年大模型技术格局演进2026年3月成为全球AI发展的关键时间节点,大模型技术呈现三个显著突破:国产模型首次在综合评测中超越国际主流产品,上下文窗口突破百万token量级,以及智能体开发框架的爆发式增长。这些进展标志着AI技术…

2026/7/24 6:44:12 阅读更多 →
深度学习与SHAP在西班牙电力市场价格预测中的应用

深度学习与SHAP在西班牙电力市场价格预测中的应用

1. 项目背景与核心价值西班牙电力市场的电价波动受多重因素影响,包括可再生能源发电占比、负荷需求变化、气象条件等。传统统计方法如ARIMA在预测这类非线性、非平稳时间序列时表现有限。深度学习模型凭借强大的特征提取能力,成为解决这一问题的有效工具…

2026/7/24 6:44:12 阅读更多 →
C++网络编程实战:基于cpp-netlib构建高性能HTTP代理服务器

C++网络编程实战:基于cpp-netlib构建高性能HTTP代理服务器

1. 项目概述:为什么cpp-netlib值得一试?如果你正在用C写网络应用,大概率绕不开一个灵魂拷问:到底该用哪个网络库?是直接上ASIO,还是用libevent、libuv?又或者,自己手搓socket&#x…

2026/7/24 6:43:12 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻