索引是什么?是帮助MySQL高效获取数据的数据结构

数据库中的表,在我们看起来是一行紧挨着一行的,但是在硬盘中,都是以链表的形式存储的,不适用索引,我们一行一行的查找数据,每一行从硬盘从读取到内存中,比对是否是我们想要的。磁盘IO性能是比较慢的。我们利用索引高效的获取数据。索引一般也比较大,也是放在硬盘上的。但是可以减少IO的次数。
为什么选择B+树?不用xx树?
这里所讲的树,默认都是对于任何一个节点,左节点小于根节点,右节点大于根节点,方便搜索

为什么不用平衡二叉树?
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。解决了二叉查找树退化成链表的问题,
把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是插入和删除时节点时,频繁的旋转操作会浪费很多时间。实现起来比较麻烦,而且需要旋转的次数不能预知。

有了上面的几个性质作为限制,即可避免二叉查找树退化成单链表的情况。但是,仅仅避免这种情况还不够,这里还要考虑某个节点到其每个叶子节点路径长度 的问题。如果某些路径长度过长,那么,在对这些路径上的节点进行增删查操作时,效率也会大大降低。这个时候性质4和性质5用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。原因如下:
当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质4限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的。
红黑树和平衡二叉树的区别:
1、红黑树放弃了追求完全平衡, 追求大致平衡 ,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。 由于它的设计,任何不平衡都会在三次旋转之内解决
2、平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦, 每次插入新节点之后需要旋转的次数不能预知。
然而,红黑树毕竟还是二叉树,一个结点最多拥有两个直接子结点,当我们有大量数据的时候,树的高度还是过高,磁盘IO的次数还是很高。一次磁盘IO的操作是很耗时的。
B+树的理解

磁盘中,一页的大小是16KB,一页(B+树中的一个节点)可以存放大约16KB/(8+6)B = 1170个索引,第三层每个节点都要存真正的数据,就算一行数据占1KB,一个节点也能存16个数据。那么三层的B+树,能存放2000w的数据,查找一个数据最多只需磁盘IO三次。这就是建立索引的好处。
如果所有的非叶子节点都常驻内存的话,那么只需要磁盘IO一次


因为B树,非叶子节点也存储了数据,假设一条数据的大小仍为1KB,那么一个16KB的磁盘页只能存放16个数据,如果想要存储2000w条数据,那么16的N次方 = 2000w,计算发现,树的高度N会非常大。而查找效率主要取决于树的高度,所以不用B树
B+树的高度,由非叶子节点能存放多少元素决定的,非叶子节点存放越多的元素越好。所以把真正的数据都放到非叶子节点。
聚簇索引(聚集索引)、非聚簇索引
存储引擎是针对数据库表的,不是对于数据库的
MyISAM引擎
MyISAM引擎就是非聚集索引,它的所有数据和存储索引的数据是分开的,需要回表才能查询到一条完整的数据


InnoDB引擎:聚集索引
聚集索引是包含表的全部信息的,包含不完整的就是非聚集索引
InnoDB一般就只有一个聚集索引,就是那个主键索引
聚集索引的定义:就是建立的索引中,叶子节点包含了完整的数据记录


为什么InnoDB表必须建主键?如果不建主键,InnoDB会自动帮我们找一列所有数据都不一样的列,作为构建B+树的非叶子节点,用于加快查找数据。如果所有列都没找到,,InnoDB会自动帮我们建一个隐藏的rowId,作为构建B+树的非叶子节点。
为什么推荐使用整型的自增主键?不推荐使用uuid作为主键呢?
查找数据的过程中有很多次的比大小,uuid是一个字符串,作为B+的非叶子节点里面的数据时,比大小,没有整型数字快。
二级索引(也是非聚集索引)都要进行一次回表操作

索引方法还有hash方法,为啥不使用?不支持范围查询


使用B+树,查找到一个叶子节点后,只需要跟着的指针走,就可以很快的找到想要的数据,对于范围查找很方便。
B树对于范围查询也很慢,当查询完一个磁盘块的时候,就又要从根节点开始查找后续的数据。所以很慢。

为什么主键要自增呢?
插入一个主键自增的节点,插入的效率更高,对于B+树的,如果从中间插入,那么B+树可能需要拆分节点和移动数据,效率不高。
对于主键索引,主键一直自增,插入到B+树中,直接添加新的叶子节点就可以了
为什么非主键索引结构叶子节点存储的是主键值?
主要是为了节省磁盘存储空间,没必要再存储一份完整的数据表
工作中用的最多的是联合索引,也叫复合索引
多个字段共同组成一个索引
如果一张表有5个字段,一般不建议使用单值索引,分别为每个字段建立一个索引,而是通过联合索引,将两三个字段放在一起,建立一张索引
为什么 联合索引, 查询时要满足最左前缀原则?
对于这样的一个基于联合索引建立的B+树,一定是先比较name,当name一样的时候,才会比较age,当age一样的时候才会比较position,整个索引的非叶子节点都是基于这样的规则。

当跳过name字段,直接查找age=30的数据时,会发现,当你找到一个age=30的数据时,可能b+树中还有很多的age=30的数据,这样如果要查全所有age=30的,就需要全表扫描
