数据库索引的简单理解
索引其实就是一种排序的数据结构
数据库中的数据放在哪里
- .frm 表的结构信息
- .ibd 存储索引和文件信息
-
数据库中数据一般都存放在硬盘中,而不是内存中,每读取依次数据中的数据,叫相当于要操作一次I/O操作,速度较慢。 应用程序发起I/0操作去调动内核,找到对应的驱动程序把数据加载到内核的内存中,然后将数据复制到mysql的内存中。
-
磁盘访问原理
操作系统一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。
如果数据不在同一个磁盘块上,那么通常需要移动制动手臂进行寻道,而制动手臂因为其物理结构导致了移动效率低下,从而增加磁盘数据读取时间。B+ 树相对于红黑树有更低的树高,进行寻道的次数与树高成正比,在同一个磁盘块上进行访问只需要很短的磁盘旋转时间,所以 B+ 树更适合磁盘数据的读取。
-
磁盘预读特性
为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的磁盘旋转时间,速度会非常快。并且可以利用预读特性,相邻的节点也能够被预先载入。
MySQL 索引
为啥要使用索引
- 数据太多的话,如果进行全盘扫描,然后进行的I/O操作的次数过多,会导致速度过慢
索引使用的条件
- 对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效;
- 对于中到大型的表,索引就非常有效;
- 但是对于特大型的表,建立和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。
B树
B树相对于平衡二叉树,每一个结点存储了更多的数据,怎木说呢,其实就是过根据我们自定义的主键,然后节点关键字是按递增次序(主键)排列,并遵循左小右大原则。
查找顺序的话,就是从根节点开始然后判断大小,顺次(比较大小)遍历下去找到我们想要找到的结点
每个页大小一般不超过4KB,一个结点一般不超过16KB
B+树
B+Tree 索引是有序的,会将相邻的数据都存储在一起
B+树是B树的一个升级版本,比B树更加好用。B+树的非叶子结点只会存储索引,而不会存储数据,而且叶子节点上包含了所有的索引和数据。
并且同一个层次的结点都根据它索引的大小进行排序,并且有双指针互相指向。
B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
B+查找数据的时候只需要从根节点根据二分法来做遍历,然后最后到叶子节点
B+树如果做全表扫描的时候,只需要遍历根节点就可以了,而不需要像B树一样从根节点开始遍历。
B+树之聚合索引
聚集索引:指索引项的排序方式和表中数据记录排序方式一致的索引。
而B+聚合索引所代表的其实就是在叶子节点存储的是数据表的索引和数据表数据在同一块地址内,索引顺序其实和物理顺序是一致的
B+树之非聚合索引
非聚集索引: 索引顺序与物理存储顺序不同
B+树的非聚合索引,其实就是叶子节点存储的是数据表的索引和指向数据表存储数据位置的引用。
hash索引
其实就和HashMap的原理差不多,计算索引的hash值(方法一般就是MD5或者CRC),然后根据hash值将数据插入到具体的位置,其实这样的话对于我们数据表查找单个数据是非常快的(只要等于号就可以了),但是当我们的查找语句中有类似于大于号小于查找的时候,就出现问题了,我们如何去确定数据就成为了问题。
-
键值唯一,hash索引有这个明显的绝对优势
-
无法完成范围i查询检索
-
无法利用索引完成排序,以及like的模糊查询
-
不支持联合索引
-
如果发生hash碰撞,索引效率低。
设置主键为自增int型
- 主要原因就是我们根据所设置的主键来查找数据,而数据库底层一般都就是B+树索引(一般都为聚合索引),如果设置成主键设置成自增int型话,是非常好查找的,并且在根据主键插入数据的时候,我们大多情况下只需要将数据直接接在叶子结点的最后面就可以了。
- 而如果我们将主键设置成UUID的时候,我们插入数据的时候,B+树的叶子节点是从左往右依次递增的,而UUID就可能插入到叶子节点的中间,而每一个页,也就是每一个数据块规定大小有16KB,若插入到中间的时候,就可能会导致数据块的大小溢出,而可能导致,我们发生B+树的叶子结点的层次向下移动(一个变成两个了,然后就扩展到下面了,导致其他的也到下面了,可以这样简单理解)。
- 我们删除一个带主键3的数据,然后在去添加一个数据的时候,发现其实已经无法添加主键为3的数据了,在我看来其实底层也是为了减少B+树叶子结点的移动,而导致从新平衡B+树。
索引优化之最左前缀原则
在数据库中数据较大的时候,有可能会有使用多个字段构成一个主键,然后用主键做成索引。因为主键中有多个字段,而B+树构只能根据一个值来确定索引关系,所以数据库依赖联合索引的最左字段来构建。
我们创建一个(q,w)的联合索引,我们构建索引的时候,现根据q的大小来进行排序,然后如果q的值相等,再根据w的索引来排序。(注意不会出现q和w值相等的情况出现,因为是主键)。这就可以被称为最左前缀匹配原则,即使我们构建了多个字段来构成索引,依旧是遵循这个原则。
知乎大佬的一篇文章:对最左前缀讲的很清楚。
[]: https://zhuanlan.zhihu.com/p/142852474