【刷题Day02】MySQL的索引和B+树

为什么 MySQL 选择使用 B+ 树作为索引结构?

深入——数据库常见的数据结构

  • 链表
    • 时间复杂度O(n)
    • 随机读的场景,数据量大时效率低
    • 空间利用率不高,要存储自身数据和下个节点指针
    • 事务支持受限,由于数据分散存储、指针的存在,实现事务的特性面临困难:在一个事务中对多个链表节点进行修改时,要保证所有修改要不全部提交,要不全部回滚,需要复杂的机制跟踪和管理,且在并发情况下容易出现数据不一致
      事务需要保证数据的原子性、一致性、隔离性、持久性
    • 碎片问题严重:链表在内存的存储并不是完全连续的,容易导致碎片化的产生,浪费存储空间、影响数据的访问效率。读取数据时需要跳过碎片节点,增加I/O操作和CPU的处理时间,同时整理碎片需要额外的开销,也有可能影响数据库正常运行
  • 红黑树:在满足红黑节点的五条性质的情况下形成的近似平衡的二叉树
    树在没有调整的情况下可能退化成链表,因此需要红黑树
    • 时间复杂度O(logN)
      - 性质:
      - 节点为红黑色
      - 根为黑色
      - 叶子节点(外部节点、空节点) 都是黑色
      - 红色节点的子节点都是黑色、红色节点的父节点都是红色、从根节点到子节点的所有路径上不能有两个连续的红色节点
      - 从任一节点到子节点的所有路径都包含相同数目的黑色节点
    • 优点
      • 保证最坏情况下的性能(树的大致平衡确保时间复杂度)
      • 自平衡:插入删除后,通过旋转和重新着色自动维持平衡,无需额外的操作与维护(但还是需要消耗性能)
      • 数据结构简洁:节点只需要额外存储一个颜色位,比其他平衡树内存开销小
    • 缺点
      • 磁盘I/O效率:二叉树,节点只存储键值和指向左右子节点的指针,数据库中数据多存储在磁盘上,磁盘I/O的时间成本高,红黑树的节点层次多,查找、增删等操作需要多次磁盘I/O获取不同节点的数据
      • 数据存储结构:空间利用率低,且红黑树的节点大小固定,面对不同大小的数据记录不够灵活
      • 并发控制:红黑树的结构调整涉及多个节点的修改,并发操作时容易出现数据不一致,需要较为复杂的锁机制。
  • B树**(多叉树、平衡多路查找树)**——MySQL(B+树)、PostgreSQL(B-link树):
    m阶的B树需要满足:
    - 每个节点最多只有m个子节点
    - 每个非叶子节点(除了根)具有至少m/2子节点
    - 如果根不是叶子节点,则根至少有两个子节点
    - 具有k个子节点的非叶节点包含k-1个键
    - 叶子都出现在同一水平,没有任何信息(高度一致),平衡树
    • B+树与B树的不同
      • 数据存储位置:B树中,数据项存储在叶子节点和非叶子节点上,B+树中,数据项只存储在叶子节点上,非叶子节点中只包含键值信息,使B+树可以在内存中存放更多索引页,减少磁盘查询次数
      • 叶子节点指针:B树的叶子节点之间没有指针连接,每个叶子节点独立存储数据项。B+的叶子节点通过指针连接成一个链表,可方便地进行快速查询。B+树的非叶子节点存在连接
      • B+树查询时间更平均稳定,都需要从根节点扫描到叶子节点,而B树在非叶子节点就可以找到对应数据返回
    • B-link树
      • 在B+树的基础上进行了并发优化,其SMO(Split、Merge、Redistribute)操作可以自底向上加锁,不必像B+树那样自顶向下枷锁,避免B+树中并发控制瓶颈——PostgreSQL从一定程度上说,并发写入效率高于MySQL
    • MySQL为什么不用B树?:
      • B+树的叶子节点之间通过双向指针链接形成链表,在范围查询时更高效,通过遍历叶子节点,可以获取连续的数据项,不需要回到非叶子节点
      • B树每个节点都存储数据,节点的空间利用率不是特别高,树高相对更高,而B+树只有叶子节点存储数据,非叶子节点只作索引,使相同数据量下B+树高度更低,查询时I/O次数更少,提高了查询效率,更契合数据库存储数据量大且需要频繁查询的特点
      • B+树子节点存储了全部数据,并按序排列,方便排序等操作,数据冗余存储在叶子节点上,很多查询场景下更有利于快速定位和获取数据,在数据的查找定位方面更加方便
    • MySQL为什么不用B-link树?:带来的事务管理机制更复杂,由于B+树已经可以满足需求,所以不需要更加的B-link树进行重构
    • MySQL为什么不用红黑树?:
      • 计组角度:
        • 磁盘I/O性能:计算机的存储包括高速缓存、内存和磁盘等。磁盘I/O速度较内存很慢,所以减少磁盘I/O可以提高性能。
          • **B树和B+树的节点可以存储多个键值对和指针,能有效利用磁盘块空间,**并减少树高减少磁盘I/O操作。
          • 红黑树节点只存储一个键值和少量指针,且树高相对较高,大规模时需要更多磁盘I/O操作
        • 局部性原理:B树和B+树的节点通常可以存储多个数据元素,读取一个节点时,会将多个相关数据一起加载,有序访问这些数据时可以直接从内存读取,减少磁盘I/O。红黑树节点存储数据较少,无法充分利用局部性原理
          计算机访问数据时,有局部性原理,即一个数据被访问,在不久的将来,其附近的数据也可能被访问。
      • 数据结构角度(从增删改查考虑)
        • 查找:B树和B+树可以通过遍历节点和指针实现高效的范围查询,且B+树中范围查询会更方便,而红黑树使用中序遍历,没那么方便
        • 修改(插入删除):B树和B+树虽然可能需要进行节点的分裂和合并,但其节点可以存储多个键值对,调整的频率较低。红黑树则相反。

总结:

  • 比起红黑树
    • B+树的节点存储多个键值对和指针,有效利用磁盘块空间,相同数据量下树高更低,查询时I/O次数更少
    • B+树的节点可以存储多个数据元素,读取一个节点时,会将多个相关数据加载,减少磁盘I/O
  • 比起B树
    • B+树的叶子节点之间存在双向指针链接,在范围查询时更加高效
    • B+树只有叶子节点存储数据,非叶子节点只作索引,相同数据量下高度更低,查询时I/O次数更少
  • 比起B-link树
    • B+树已经够用,使用B-link树的事务管理机制更加复杂,没必要再重构。

MySQL 索引的最左前缀匹配原则是什么?

  • 定义:使用联合索引时,查询条件必须从索引的最左侧开始匹配,如果一个联合索引包含多个列,查询条件必须包含第一个列的条件,然后第二个列,依次类推。
  • 原理:联合索引在B+树中排列方式有序。因此组合索引能够从左到右依次高效匹配,跳过最左侧字段则无法使用该索引
    先按a值排序,如果a相同,按b排序,依次类推
  • 速记:刘备(大哥)不能出事。
  • 情况:CREATE [UNIQUE | FULLTEXT] INDEX 表名(a, b, c);
    • 查询中有最左列:
      正常情况略
      • WHERE a = 1, c = 3;
        • MySQL5.6前,只能用a=1,但之后优化(索引下推),即查到a=1的数据后,用c过滤不符合的数据
          索引下推:允许MySQL使用索引查找数据时,将部分查询条件下推到存储引擎层过滤,减少需要从表中读取的数据行,减少了I/O,减少回表查询、提高查询效率(本该由Server层操作,交给存储引擎层因此叫“下推”)。
      • 范围查询:WHERE a > 1, b = 2, c = 3;
        停止匹配——a可以用上联合索引,但b、c不行。因为a筛选后,b、c无序了,无法利用索引查询。
        如遇到>=、<=、BETWEEN、前缀like(xx%)的范围查询,不会停止匹配,因为这些查询中包含等值判断,可以直接定位到某个数据,之后往后扫描即可
      • WHERE a = 1, b = 2, c > 3;
        a和b是等值查询的情况下,c有序,可用上索引
    • 查询中无最左列:不走索引
      • 优化:MySQL8中,会先统计最左序列的不同值,再自动补齐最左序列(最左序列的值需要少,不然也和直接扫盘区别不大)

MySQL 三层 B+ 树能存多少数据?

在MySQL的InnoDB存储引擎中,B+树默认数据页大小为16KB(可以通过修改配置文件my.cnf或my.ini修改)

[mysqld]
innodb_page_size = 16K

条件梳理
B+树,非叶子节点不存数据,只存指针和索引键,那么第一层根节点和其往下发散的第二层,用来计算能发散出多少个叶子节点第三层用来计算能存多少数据。分别得到以下条件:

  • 每个节点页大小:16KB
  • 每个内部节点(非叶子节点)存储指向子节点的指针索引键指针默认6字节,索引键(主键)一般为BigInt,即8字节
  • 每条数据记录的主键和数据大小为1KB

那么每一个内部节点可以发散出去的子节点(指针+索引键组合)有:
(16KB × 1024) / (6 + 8) = 16384B / 14 ≈ 1170个
第一层和第二层共有:
1170 × 1170 = 1368900个
第三层的叶子节点中可以存放16KB/1KB=16条数据,即共有
1368900 × 16 ≈ 2000w
约2000w条数据

补充——回答问题的模板:计网知识+B+树知识+业务知识
如:为减少磁盘IO的次数,B+树层不宜过高,以3层为计算,设每条数据记录为1KB,最终可存储约2000w条数据。具体存储量要看具体业务,根据业务大小决定最终可存储的记录条数。

你可能感兴趣的:(面试题,mysql,b树,数据库)