b+tree演进

innodb

大家都知道,mysql索引由存储引擎层实现,常见的是innodb。

索引最主要得作用是提升访问效率(类似于书籍目录,比如新华字典,有字母索引,也有笔画索引),索引的定义:

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息

所以,索引是数据结构。

索引注意点

  • 创建索引要大量耗时(如果是大数据的情况,要慎重)
  • primary,唯一且不能为空。 fulltext index,一般不用
  • 不要使用随机无序的字段做索引(写入会产生大量磁盘碎片,分裂问题和单链表一样,导致大量操作)
  • 和业务无关的自增值当主键。
  • 不是所有存储引擎都支持索引,也不是所有存储引擎都是btree实现(但是主流是)
  • innodb 索引就是数据,数据就是索引(数据在叶子节点上)
  • 不要在离散度小的的数据列上建立索引
  • 联合索引有最左匹配原则
  • 覆盖索引,select key from table,key全部在索引中,避免了回表
  • 回表(二级索引查询聚集索引(主键索引))
  • 联合主键索引,看业务场景,一般不推荐用
  • 随机无序的值,不适合主键索引

b+tree演进过程

分析其他算法

二分查找法,效率提升,但是数组不好维护

链表,有局限性,查找链路过长

因此产生了二分查找树,binrary search tree (BST),并且天然有序。

二分查找树依旧摆脱不了树深度问题(二叉树问题),因此,平衡二叉树出现。

一个节点只能存一个数据的话,会造成大量的页浪费。

因此BTREE产生,一个树节点的大小设计为16kb=>16384 bytes。一个节点存储了 16384 / len(key) 个索引。

分裂、合并保持平衡和平衡二叉树保持一致。

B+Tree非叶子节点只保存索引,并且分为聚集索引和非聚集索引。非聚集索引的叶子节点保存的是聚集索引的地址。聚集索引的叶子节点保存的是实际存储的值。

b+tree特性

  1. 关键字数量和度的数量是 N:N,树的深度更小
  2. 只有叶子节点才有数据(io次数很稳定,就是树的深度,并且使中间节点能存更多,能更矮更胖【树形状】)
  3. 叶子节点有双向指针(遍历数据更快,只需要从叶子节点最左边开始即可)

一些其他question:

  1. 要是一行数据大于16k咋办,一个page放不下怎么办,分裂成多个节点吗?

https://gper.club/answers/7e7e7f7ff1g59gc0g6e 一步步来分析:

1)InnoDB Page默认大小为16KB = 16384 bytes,叶子节点最大为 16384 字节。
2)如果一行数据的大小超过了page的可用空间,怎么办?比如一行数据包含了一个varchar字段,varchar最大长度65536 bytes(实际是65532bytes),如果字段达到这个长度,显然一个page存不下这行数据
3)这个时候会发生行溢出( overflow pages),数据存储在所谓的溢出页(off-page)中
4)不同的行格式(row format)对于行溢出的处理不同 参考官网 https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html 这里有一篇中文的行格式的文章:https://www.cnblogs.com/25-lH/p/12739837.html 页溢出确实会影响性能,尽量缩减字段长度。
  1. 为什么二级索引不存主键所在的叶子节点的地址呢?

聚集索引的树可能会发生变化,存地址的话,不可靠,或者增加了维护性

  1. 没有主键索引的时候怎么办?

_row_id,会自动创建一个索引

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章