1. 理解 MySQL 中的索引
? 如果把 MySQL 想象成一本书,那么这本书的目录就相当于 MySQL 的索引。
? 我们知道如果阅读一本书,我们可以通过这本书的目录来快速的查找到自己上次所阅读到的内容,这样就使我们阅读的效率更高。 同样的 MySQL 的索引也是这个道理,它的出现也是为了让我们在数据库中的查找提升效率。
? 但是我们还是需要明白一点,这不是没有代价的。在书上添加目录,就会使得整本书的页数增加;同理,在 MySQL 中添加索引,也会格外的占用一些存储空间,如果数据量越大,那么所消耗的存储空间也就会越大。
? 同时,当我们对一本书中的内容进行增删改的操作时,我们也需要同步的对书的目录进行增删改的调整,这和 MySQL 中的索引一样,就会导致 数据库 中 增删改 的操作效率变低。
索引带来的益处:提高了查找的效率。
索引带来的坏处:占用了更多的存储空间,使增删改的操作效率降低了。
? 从上面来看,好像添加索引 好处 少于 坏处 ?但为什么 MySQL 中还会使用 索引 呢?
? 因为,我们在日常操作数据库时,我们发现对数据库进行查找操作更加频繁。相较于 查找,增删改 的操作次数就比较少了。并且,如果数据量非常大的时候,这时候,查找 提升的效率就会更加明显。
注意:添加索引 最好在建表时就考虑清楚,因为一旦添加索引 或 不添加索引 后 ,数据库经过了一段时间的使用。里面的数据量可能很大,这时我们再想要 添加索引 或者 删除索引,这就是一个效率很低的操作。更有可能将 磁盘IO 和 网络IO 给拉满,从而使数据库崩溃掉。
2. 和索引相关的一些 SQL 语句
3. 索引背后的数据结构
我们在学习 java 语言的时候,我们也都学习过一些数据结构:
那么这些数据结构是否就是 MySQL 中索引所使用的数据结构呢?
- 首先,我们需要明确,为什么需要有索引?因为我们需要提高数据库中查找的效率。所以可以直接排除 顺序表 和链表 。在 顺序表 和 链表 中,我们想要查找一个值(注意这里我们默认的是查找一个值,而不是下标),它需要将 顺序表 或 链表 中的每个值都遍历一遍。此种方式并没有提高查询的效率。
- 然后就是 堆 这种数据结构,学过数据结构的小伙伴们都知道,堆的特点 就是 找到 最大值 和 最小值。而这种特点并不能帮我们提高 查询的效率,所以也不合适。
- 接着,我们考虑 哈希表 。哈希表 的时间复杂度是 O(1) ,虽然效率变得很高了,但是又出现了一个问题,那就是**哈希表 只能查到具体的某个值,而不能对一个范围进行查询判定。**而这就使查询的功能不完整了。
- 最后就是 二叉树搜索树 了,我们知道 二叉搜索树 的查询方式 很像 二分查找 ,查询速度也比较快,**但当这棵树是一颗单分支的树时,查询方式,也就变成了遍历所有的值,它的查询效率也就很低。**那么,既然单纯的二叉搜索树不行,我们也就可以使用 二叉搜索树 的升级版啊 !!!
- 先考虑 AVL 树(可以看成 二叉搜索树的升级版),**AVL 树的要求是:在二叉搜索树的基础上,需要满足 整棵树 或者 每一颗子树 ,它的 左子树 与 右子树 的高度差不大于 1 。**这时虽然解决了 单分支 的情况,看似最终的问题得到了解决。但其实不然,它有两个问题:
- 第一个问题:它规定的太死了,我们本来只需要解决一下,出现极端情况的问题,结果 AVL 树这里直接给卡死了。
- 第二个问题:如果数据库中的数据量很大的时候,整棵树的高度就会很高。那么也就意味着我们需要进行比较的次数也就会增加。须知道 数据库 的数据都是存在 磁盘 上的,如果需要比较,那么就需要通过 磁盘IO 来比较,而不是直接在内存中进行比较。而且在 内存 中比较的速度比在 磁盘 中比较的速度快了 1000 倍 至 10000 倍。最终还是会导致效率低下。
- 然后就是 红黑树 ,它相较于 AVL 树,就是使的要求卡的没有那么死了。也就是解决了 AVL树 的第一个问题。但对与第二个为题,它也是无能为力。所以依然不行!!
? 从以上的考虑来看,好像我们以前所学的数据结构都不能满足数据库索引所需要的要求。
? 但我们从分析的过程来看,还是会发现,相较于其他的数据结构,二叉搜索树 已经快满足索引的需求了,只是受困于 当数据量很大时,整棵树的高度会很高 这个问题。那么有没有一种数据结构能解决这个问题呢???
? 答案是肯定的!!!
? 既然 二叉搜索树 解决不了这个问题,那么我们就可以使用 n叉搜索树 来解决这个问题!!!
? n叉搜索树 :也叫 B 树 或者 叫 B- 树。它的存储方式不在是一个节点一个数据,而是变成了一个节点中存储多个数据。分支则是各个数据的范围。(分支的个数 = 父节点内数据的个数 + 1)
如图:
-
上图只是一个简单的 B数 (还有一些分支并没有补齐),但它已经清楚的描述了一颗 B树 的特点。我们可以很清晰的看到 ,整颗树的高度已经大大降低了。B树已经解决了树高的问题,但是我们如果进行范围查询,那它还是有问题,比如上面这棵树我们查询到 2 < n <= 16 的范围时效率太低了。并且我们还会发现整棵树上每个节点的 载荷 太高了。
- 载荷 :因为我们是用树的方式来组织数据的,但是我们需要存储的数据,往往不是单纯的一个数字或字符,而是一些数据的集合,比如 上图中的 0 号节点,它不是只存了一个编号 0,它的里面还有编号0的相关信息。这些统称为载荷。
-
那么又怎么解决上面的 范围查找 和 载荷 的问题呢? 接下来就引入了 B+ 树,这种树好像就是为了数据库查询而产生的。
如图:
- 分析:B+ 树的结构和 B 树是有所不同的:
-
- 整棵树所有的值最后都会在叶子节点上体现出来。
-
- 每颗子树所分成的区域范围相比较 B 树 少了一个。(B+树 是节点中有 n 个值,则分成 n 个区域)
-
- 最后会把叶子节点给连接成一条链表。
观察上面 B+ 树 的结构,可以发现就已经把上面的两个问题给很好的解决了。
范围查找 :通过最后将叶子节点给连接成一条链表,我们就可以很高效的找到我们需要的范围数据。
载荷 : 由于父节点上的值都会在子节点上体现,也就是说叶子节点上的值包含了整颗树的值,那么我们就可以在非叶子节点上只存储一个标识符,而不用将非叶子上的每个标识符的信息都放到节点上,如果标识符够小,我们可以直接在内存中进行比较,这样基本不会占用磁盘IO。使得查询效率有极大的提高!!!
总结:数据库索引 背后的数据结构是 B+ 树。
|