当数据库的数量太大,sql查询速度比较慢的时,大部分人应该都回给相关的字段添加索引,那索引是什么呢?
本文以mysql数据库为例进行相关的闲谈;
索引是什么?
索引是一种数据结构,一个高效获取数据的排好序的数据结构;
常见的索引数据结构:
二叉树
红黑树
Hash表
B-Tree
我们知道MySQL数据库底层默认使用的索引数据库结构是B树中的B+树;那为什么不是其他几种数据类型呢?
假设我们要存储的数据如下:
col1 | col2 |
---|---|
1 | 35 |
2 | 17 |
3 | 24 |
4 | 45 |
5 | 15 |
6 | 60 |
如果我们不采用比较好的数据结构的话,数据库中查找数据时就会一条条去查询符合条件的数据;
二叉树
我们使用col2列做索引列,大致的二叉数如下:
那如果我们使用col1作为索引列呢?
二叉树如下:
我们发现如果我们使用连续递增的字段作为索引列时,二叉树就会变成一个线性表,和我们全表扫描一样,其效率也较低;
那如果采用红黑树呢?
红黑数
红黑树是每个节点都带有颜色属性(颜色为红色或黑色)的自平衡二叉查找树,满足下列性质:
1)节点是红色或黑色;
2)根节点是黑色;
3)所有叶子节点都是黑色;
4)每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5)从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
使用col2列的红黑树结构:
使用col1作为索引列的红黑树如下:
我们知道红黑树是会旋转来维护其平衡,那为什么MySQL数据库没有采用红黑树这个数据结构呢?我们想一想,如果数据很大的时候,红黑树的高度是不是也会随之变高,那当我们查找的元素在叶子节点呢,就需要经历树的高度次的IO,效率可想而知。红黑树的高度不可控,IO查找的次数也就不可控,数据量大的情况下就不适合;那如何对红黑树进行改造,可以让存储数据量很多,又希望IO读取次数是可控的?假如我们将每个节点横向存储更多的数据,树的高度是不是也会随之降低,其B-Tree其中就采用了这种思想;
B-Tree
B-Tree:
1.叶节点具有相同的深度,叶节点的指针为空
2.所有索引元素不重复
3.节点中的数据索引从左到右递增排列
我们先看下B-Tree大概长什么样;
我们看到同样的数据情况下,B树的高度明显比红黑树要低,从而查询速度会要快,那为啥MySQL底层使用的不是B树而是B+树呢
我们看下B树每个节点的结构如下
0001 |
---|
data |
在innodb存储引擎下,在每一个节点中还会将其索引对应行的数据也进行保存;我们都知道innodb的页块大小默认为16kb,如果data空间占用比较大,那横向存储的节点是不是就越少,那是不是树的高度也是不那么可控呢,但是还会比红黑树要矮; |
B+Tree(B-Tree变种)
B+Tree特性:
1.非叶子节点不存储data,只存储索引(冗余),可以放更多的索引
2.叶子节点包含所有索引字段
3.叶子节点用指针连接,提高区间访问的性能
B+树对B树进行一些改变,我们结合上面的B树可以看出:
非叶子节点不存储data,这样我们横向可以存储多个节点,从而树的高度是可控的,其叶子节点包括所有索引列及对应的数据data;并且我们可以发现B树的叶子节点之间是没有指针连接的,而B+树的叶子节点指针相连;而且B+树对范围查询更加有效。
假设我们查询select * from table where col1 > 1;
如果我们使用B树结构查询的话,是需要反复从根节点到叶子节点查询的,而B+树的话,我们找出第一个符合的条件的叶子节点后,就直接使用指针查询,不需要重新从根节点开始查询;
至于MySQL默认没有选择Hash这种结构呢,大家熟悉HashMap底层结构的话就知道Hash这种数据结构会出现hash冲突问题,最重要的是我们使用Hash表这种数据结果无法支持范围查找、模糊查找等场景。
文章仅仅是介绍的主键索引在数据结构上结构,联合索引(辅助索引)可阅读:联合索引(辅助索引)在B+树的结构