MySQL 索引原理
索引是以字段为键、记录为值的 B+ 搜索树。
一、索引的减少 I/O 设计
从硬盘搜索读取查询记录时,由于一次硬盘读取数据到内存的时间是内存里操作数据时间的 10 万倍,MySQL 通过索引数据结构的设计减少了查询记录的硬盘 I/O 的次数。
深入解析 MySQL 索引底层结构 B+ 树。通过对比 B 树,说明 B+ 树如何利用非叶子节点存储键值、叶子节点存储数据及链表连接来降低磁盘 I/O 并支持范围查询。文章涵盖索引的查看、创建(含大表安全策略)及删除操作,阐述数据库性能优化的核心原理。

索引是以字段为键、记录为值的 B+ 搜索树。
从硬盘搜索读取查询记录时,由于一次硬盘读取数据到内存的时间是内存里操作数据时间的 10 万倍,MySQL 通过索引数据结构的设计减少了查询记录的硬盘 I/O 的次数。
保持硬盘单次最大读取量(页)最大量地进行读取,以减少读取 I/O 次数。每个 B+ 搜索树节点的存储空间是一个页,即对应每次读取完一个 B+ 搜索树节点的总页存储空间的内容量。
在搜索树中,查询时会避免遍历地每次往正确范围、正向增长搜索到概率的方向进行搜索,直到最后搜索到也会精确匹配。
搜索树结构维护了记录值以字段键的有序性,支持以字段的范围查询记录与以字段的排序记录。
对比哈希表: 哈希表虽然能实现一次硬盘读取就可 O(1) 地查询到记录,但只能精确匹配,内部是以哈希函数维护的无序数组,无法范围查询,也无法进行排序。
在一次读取的一个节点中放多个排布搜索对象分多叉,能一次更多对象的排布完、一次更多对象的搜索完、一次搜索接往到更加细致确定的范围区间里来。
键值对单位存储
键值对合空间如果很小,节点可以直接大量存储键值对,每个节点排布海量 N 个键值对 N+1 次方地向下分支排布搜索数据来完成海量键值对数据的入树的排布。
弊端:
但在数据库中,一个值记录的空间很大,一个键字段的空间很小,键值对的合空间很大:
一个节点一个页的存储量放不了多几个键值对排布分叉的,每个节点能存储下来的排布数据少向下分支少向下搜索的区间广,需要往下分支很多次才可分布排完数据,树的高度会很高,处在叶子节点的大部分键值对要硬盘从顶层多次读取搜索到底层才可搜索到,硬盘 I/O 总体会很高。
记录在全节点 -> 不稳定
作为查询搜索的结果的键值对里的值记录,与键一块直接存储在出现的树节点中,少部分的在非叶子节点的键值对可以少量 I/O 地往下读取搜索到,大部分的在叶子节点的键值对需要大量 I/O 地读取到底层,查询的时间开销不稳定。
键与值分开存储
B+ 树针对数据库里值记录空间很大,一个搜索树节点无法存下过多个键值对去海量分叉排布,将键与值分开存储,键在非叶子节点搜索,值在叶子节点对应。
非叶子搜索阶段每个非叶子节点只放无记录值对应的海量键字段,一个节点一个页就可最多放多达 1600 个键字段地大量排布搜索数据细致划出排往范围地搜索。
内存中操作数据的速度虽然快,但一次从硬盘读取到内存的数据如果处理的单位个数过多,一时间内内存里也无法快速比较完个数过多的数据,所以每个节点放 1000 个键字段以 1000 的幂次方向下分支排布存储搜索的数据,3 层对应 3 次硬盘读取就可排查地搜索完分支排布到亿级的字段量。
非叶子节点内的亿级总记录个数的字段量,由于字段的空间很小,能确保所有全记录对应的字段总空间是很小的,况且缓存只对非叶子节点并未对分支到最后一层的叶子节点的记录里的字段量进行缓存,所以非叶子节点里也不会有所有记录个数对应的总字段量那么多,非叶子节点字段总空间很小可以缓存到内存中的。
首次查询: 非叶子节点字段量在首次查询时 B+ 搜索树高度次硬盘读取从硬盘把此搜索树的所有非叶子节点全部读取加载到缓存中存放。
后续查询: 在后续查询时,非叶子节点的字段数据都已加载在缓存内存中有不用再硬盘读取直接继续在缓存中对字段进行搜索常数时间,然后搜索出指定叶子节点后再对存储在硬盘的叶子节点键值对硬盘读取一次固定一次硬盘 I/O 的常数时间,时间复杂度也就成了 O(1)。
非叶子节点的所有键字段都开区间地隐藏搜索不到,每次对它们搜索完都作为查询的可能结果键以子区间最大值的形式往搜索子区间的 N 叉区域分别向下传递。
形成了非叶子节点的只往区间搜索键、键字段数据向下保留传递的搜索模式。
到叶子节点时整棵树所有出现过的父节点区间键与整棵树在叶子节点最后剩余出的区间键会构成整棵树的从左往右有序的键字段全集。
叶子节点层,键字段全集的叶子节点对应存上值记录成全集的键值对。
叶子节点之间再左右相连地连接成链表使搜索树逻辑上的有序再套上了物理相邻存储的有序,大大优化了磁盘 I/O:
搜索树范围查询数值时,避免了 B 树的范围查询回溯节点的硬盘 I/O 时间开销,而每到下一个连续数值的链表节点就对应一次硬盘 I/O。
B+ 搜索树都是在叶子节点闭键,键在叶子节点时才可以去搜索查询到的,查询会在且只能在叶子节点搜索查询到,固定了查询的时间开销。
查看表中所有的索引。
为表的指定列字段创建索引,primary key、unique、foreign key 字段在创建表时就会自动创建出索引维护。
在表创建数据空时或在表的数据量较小时就要将要创建的索引创建好。
为一个记录量很大的表创建指定字段的索引。
第一层:从创建的第 1 个顶层根节点出发,每个节点里面都有存储 1000 个字段。
第二层:第二层为第一层根节点里面存储的 1000 个排布键分出的 1000 个字段区域往下为每个区域分叉都创建一个对分到的区域再次存储有 1000 个排布键的排布划分的节点,因此第二层就共创建了 1000 个节点。
第三层:第三层为第二层的 1000 个节点每个节点都会分叉 1000 个区域每个区域对应去创建存储有 1000 个排布值的 1 个节点,第三层就会总共去创建 1000*1000 个节点。
第四层:再往下层就会去创建 100010001000 个节点。
第 N 层:以 1000 的幂次方量往下创建节点,直到叶子所有节点总共存储的字段覆盖字段全集时,该字段的 B+ 搜索树才创建好。
工作量巨大,会使服务器一时间全盘去创建索引的 B+ 搜索树而呈挂机状态。
如果就要为一个海量数据的表创建索引,正确的做法是:在另一个 mysql 服务器上创建相同结构的空表创建索引再将数据控制量地可正常维护索引地导入建树,B+ 搜索树创建好索引创建好后最后对服务器更换转到使用此索引创建好的 mysql 服务器。
删除表中的指定索引。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
在线格式化和美化您的 SQL 查询(它支持各种 SQL 方言)。 在线工具,SQL 美化和格式化在线工具,online
解析 INSERT 等受限 SQL,导出为 CSV、JSON、XML、YAML、HTML 表格(见页内语法说明)。 在线工具,SQL 转 CSV/JSON/XML在线工具,online
CSV 与 JSON/XML/HTML/TSV/SQL 等互转,单页多 Tab。 在线工具,CSV 工具包在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online