一、没有索引的时候如何查找

先忽略掉索引这个概念,如果现在直接要查某条记录,要如何查找呢?

在一个页中查找

如果表中的记录很少,一个页就够放,那么这时候有 2 种情况:

  • 用主键为搜索条件:这时就是之前文章提过的方式,页面目录中用二分法快速定位到槽,然后遍历该槽对应分组的记录,最终找到指定记录。
  • 用其他非主键的列为搜索条件:因为数据页中没有为非主键列建立页目录,无法通过二分法快速定位槽,只能从 Infimum 记录开始一次遍历单链表的每条记录,效率低下。

在很多页中查找

当表中的记录非常多,就会用到很多的数据页来存储,这时候需要 2 个步骤:

  • 定位到记录所在页。
  • 重复上述在一个页中查找的过程。

总得来说,当没有索引,我们无法快速定位到记录所在页,只能从第一页沿着双向链表(页有前一页和后一页)一直找下去,然后在每一页中重复上述的过程查询指定的记录,需要遍历所有记录,这种方式非常耗时

二、一个简易索引

既然是因为页数太多导致定位记录太慢,那如何解决呢?不妨参考一下“页目录”。

页目录就是为了根据主键快速定位一条记录在页中的位置而设置的。那么我们也可以想办法为快速定位记录所在的页,搞一个“别的目录”。

但是这个“别的目录”要想完成还得干好 2 件事。

1. 下一页用户记录的主键值必须大于上一页的

假设,每个数据页最多可以放 3 条记录(实际上可以放很多),那么现在向表里插入 3 条记录,每条记录有3个列 c1、c2、c3。为了看着方便,存储行格式也简化下,只留关键属性。注意中间3条是用户记录,首尾的2条是虚拟记录 Infimum 和 Supremum。

此时,继续插入 1 条记录。按照假设的情况,现在需要多分配一个新的页,所以 2 个页之间就变成了这样。

注意红色字体显示的2条记录,本来主键 4 的记录是新插入的,按理应该放在新的页。但是,为了满足下一页用户记录的主键值必须大于上一页的用户记录主键值,做了诸如记录移动的操作,这个过程也可以称为“页分裂”。

另外,为什么新页是页 28,而不是 11?因为页在磁盘上可能并不挨着,它们只是通过维护上一页和下一页的编号而建立了链表关系。

2. 给所有的页建立一个目录项

现在继续向表里增加数据,最终多个页的关系是这样:

因为这些页在磁盘上可能不挨着,所有想要快速从这么多页中根据主键快速定位某记录,就要给它们编制一个目录。

每个页对应一个目录项,每个目录项包括:

  • 页的用户记录中最小的主键值,用 key 来表示
  • 页号,用 page_no 表示

所以,给它们编好目录之后就是这样的关系:

那么,现在我想查找主键值为 20 的记录,具体就分两步走:

  • 先从目录项中根据二分法快速确定出主键值为 20 的记录所在目录项 3 中,且对应的页为 9。
  • 知道是在页 9,重复之前的方式,找到最终目标记录。

到此,一个简易的方案完成。而完成的这个简易目录,它有个别名,叫做索引

三、简易索引暴露出的问题

上述的简易索引是原书作者为了循序渐进的帮助读者理解而设置的内容,这并不是innodb的索引方案。

那么针对上述的建议索引,看下有哪些问题。

问题一

InnoDB 使用页作为管理存储空间的基本单位,也就是最多只能保存16kb的连续存储。

当表中记录越来越多,此时就需要非常大的连续存储空间才可以把所有的目录项都装下,这对大数据量的表来说不现实。

问题二

我们经常还要对记录执行增删改操作,会牵一发而动全身。

比如,上图中我如果把页 28 中的记录都删除,那么页 28 就没必要存在,进而目录项 2 也没必要存在。这时候就需要把目录项 2 后的目录项都向前移动一下。

就算不移动,把目录项 2 作为冗余放在目录项列表中,仍然会浪费很多的存储空间。

所以,InnoDB 的作者发现了一种灵活管理所有目录项的方式,详见下一篇。

本文参考书籍:
小孩子4919 《mysql是怎样运行的》

【Mysql】一个简易的索引方案的更多相关文章

  1. 实验楼 MySQL 基础课程 挑战:搭建一个简易的成绩管理系统的数据库

    传送门:https://www.shiyanlou.com/courses/running 介绍 现需要构建一个简易的成绩管理系统的数据库,来记录几门课程的学生成绩.数据库中有三张表分别用于记录学生信 ...

  2. mysql大内存高性能优化方案

    mysql优化是一个相对来说比较重要的事情了,特别像对mysql读写比较多的网站就显得非常重要了,下面我们来介绍mysql大内存高性能优化方案 8G内存下MySQL的优化 按照下面的设置试试看:key ...

  3. 防止服务器宕机时MySQL数据丢失的几种方案

    这篇文章主要介绍了防止服务器宕机时MySQL数据丢失的几种方案,结合实践介绍了Replication和Monitor以及Failover这三个项目的应用,需要的朋友可以参考下. 对于多数应用来说,My ...

  4. Tinyshell: 一个简易的shell命令解释器

    这是自己最近学习Linux系统编程之后写的一个练手的小程序,能很好地复习系统编程中的进程管理.信号.管道.文件等内容. 通过回顾写的过程中遇到的问题的形式记录程序的关键点,最后给出完整程序代码. 0. ...

  5. MySQL的B树索引与索引优化

    MySQL的MyISAM.InnoDB引擎默认均使用B+树索引(查询时都显示为"BTREE"),本文讨论两个问题: 为什么MySQL等主流数据库选择B+树的索引结构? 如何基于索引 ...

  6. MySql(九)索引

    一.索引的介绍 数据库中专门用于帮助用户快速查找数据的一种数据结构.类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置吗,然后直接获取. 二 .索引的作用 约束和加速查找 三.常见的几 ...

  7. express + mongodb 搭建一个简易网站 (四)

    express + mongodb 搭建一个简易网站 (四) 目前网站整体页面都已经能全部展示了,但是,整个网站还有两个块需要做完才能算完整,一个连接数据库,目前网站上的数据都是抓取的本地假数据,所以 ...

  8. MySQL慢查询优化、索引优化、以及表等优化总结

    MySQL优化概述 MySQL数据库常见的两个瓶颈是:CPU和I/O的瓶颈. CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候. 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应 ...

  9. mysql 百万级数据库优化方案

    https://blog.csdn.net/Kaitiren/article/details/80307828 一.百万级数据库优化方案 1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 wher ...

随机推荐

  1. 理解 this

    this this 取什么值是在函数执行的时候确认的,不是在函数定义的时候确认的 this 的不同应用场景,this 的指向 函数在调用时,js 会默认给 this 绑定一个值,this 的值与绑定方 ...

  2. 用Redis实现签到功能

    一.场景 在很多时候我们会遇到用户签到的场景,每天用户进入应用时,需要获取用户当天的签到状态,如果没签到,用户可以进行签到,并且得到相关的奖励.我们可能需要每天的签到情况,必要的时候可能还需要统计一下 ...

  3. springboot注解之@ConditionalOnProperty

    最近在研究springboot的源码,看到很多@ConditionalOnXxx的注解,大概明白此注解的意思,就是判断条件,这个条件就是Xxx,例如ConditionalOnProperty就是判断配 ...

  4. 「题解」agc031_e Snuke the Phantom Thief

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:洛谷 AT4695.AtCoder agc031_e. 题意简述 在二维平面上,有 \(n\) 颗珠宝,第 \(i\) 颗 ...

  5. 【Java】Debug断点调试常用技巧

    Debug操作技巧 Show Execution Point 将光标回到当前断点停顿的地方 Step Over 执行当前行代码,并将运行进度跳转到下一行. Step Into 进入到当前代码行的方法内 ...

  6. Spring WebFlux 教程:如何构建反应式 Web 应用程序

    Spring WebFlux 教程:如何构建反应式 Web 应用程序 反应式系统提供了我们在高数据流世界中所需的无与伦比的响应能力和可扩展性.然而,反应式系统需要经过专门培训的工具和开发人员来实现这些 ...

  7. Java知识复习(一)

    Java面向对象的三大特性: 封装.继承.多态. super()与this()的区别? This():当前类的实例,一个类,如果继承了父类,那么通过this既可以访问当前类的属性和方法,也可以访问父类 ...

  8. 『心善渊』Selenium3.0基础 — 9、使用Seleniun中的By类定位元素

    目录 1.使用By定位的前提 2.By定位的方法 3.By定位的使用 4.复数形式的示例 我们还可以通过Seleniun测试框架中的By类,来实现页面中的元素定位. 1.使用By定位的前提 需要导入B ...

  9. QObject::startTimer: timers cannot be started from another thread 一则输出调试:关于QT的线程关联性

    开始 今天在调试输出里看见QObject::startTimer: timers cannot be started from another thread QTimer类 从Qt的帮助文档里可以得到 ...

  10. Hadoop:什么是Hadoop??

    官方讲解: Apache Hadoop 为可靠的,可扩展的分布式计算开发开源软件.Apache Hadoop软件库是一个框架,它允许使用简单的编程模型跨计算机群集分布式处理大型数据集(海量的数据). ...