【Java开发】Java面试七大专题第10篇:4. 索引【附代码文档】

35 阅读1分钟

🏆🏆🏆教程全知识点简介:基础篇 1. 二分查找 2. 冒泡排序 7. ArrayList 8. Iterator 9. LinkedList 10. HashMap 1)基本数据结构 2)树化与退化 3)索引计算 4)put 与扩容 5)并发问题 11. 单例模式 并发篇 1. 线程状态 3. wait vs sleep 4. lock vs synchronized 虚拟机篇 1. JVM 内存结构 4. 内存溢出 5. 类加载 6. 四种引用 7. finalize 框架篇 1. Spring refresh 流程 2. Spring bean 生命周期 6. Spring 注解 7. SpringBoot 自动配置原理 数据库篇 1. 隔离级别 2. 快照读与当前读 3. InnoDB vs MyISAM 4. 索引 索引基础 5. 查询语句执行流程 6. undo log 与 redo log 7. 锁 缓存篇 1. Redis 数据类型 2. keys 命令问题 3. 过期 key 的删除策略 5. 缓存问题 6. 缓存原子性 7. LRU Cache 实现 分布式篇 1. CAP 定理 2. Paxos 算法 4. Gossip 协议 5. 分布式通用设计 6. 一致性 Hash(补充)


📚📚👉👉👉本站这篇博客:   juejin.cn/post/754466…    中查看

📚📚👉👉👉本站这篇博客:   juejin.cn/post/754466…    中查看

✨ 本教程项目亮点

🧠 知识体系完整:覆盖从基础原理、核心方法到高阶应用的全流程内容
💻 全技术链覆盖:完整前后端技术栈,涵盖开发必备技能
🚀 从零到实战:适合 0 基础入门到提升,循序渐进掌握核心能力
📚 丰富文档与代码示例:涵盖多种场景,可运行、可复用
🛠 工作与学习双参考:不仅适合系统化学习,更可作为日常开发中的查阅手册
🧩 模块化知识结构:按知识点分章节,便于快速定位和复习
📈 长期可用的技术积累:不止一次学习,而是能伴随工作与项目长期参考


🎯🎯🎯全教程总章节


🚀🚀🚀本篇主要内容

4. 索引

要求

  • 了解常见索引与它们的适用场景,尤其是 B+Tree 索引的特点
  • 掌握索引用于排序,以及失效情况
  • 掌握索引用于筛选,以及失效情况
  • 理解索引条件下推
  • 理解二级索引覆盖

索引基础

常见索引

  • 哈希索引

    • 理想时间复杂度为 O(1)O(1)
    • 适用场景:适用于等值查询的场景,内存数据的索引
    • 典型实现:Redis,MySQL 的 memory 引擎
  • 平衡二叉树索引

    • 查询和更新的时间复杂度都是 O(log2(n))O(log_2(n))
    • 适用场景:适用于等值查询以及范围查询;适合内存数据的索引,但不适合磁盘数据的索引,可以认为树的高度决定了磁盘 I/O 的次数,百万数据树高约为 20
  • BTree 索引

    • BTree 其实就是 n 叉树,分叉多意味着节点中的孩子(key)多,树高自然就降低了
    • 分叉数由页大小和行(包括 key 与 value)大小决定
      • 假设页大小为 16k,每行 40 个字节,那么分叉数就为 16k / 40 ≈ 410
      • 而分叉为 410,则百万数据树高约为3,仅 3 次 I/O 就能找到所需数据
    • 局部性原理:每次 I/O 按页为单位读取数据,把多个 key 相邻的行放在同一页中(每页就是树上一个节点),能进一步减少 I/O
  • B+ 树索引

    • 在 BTree 的基础上做了改进,索引上只存储 key,这样能进一步增加分叉数,假设 key 占 13 个字节,那么一页数据分叉数可以到 1260,树高可以进一步下降为 2

SpringDoc OpenAPI

树高计算公式

  • log10(N)/log10(M)log_{10}(N) / log_{10}(M) 其中 N 为数据行数,M 为分叉数

BTree vs B+Tree

  • 无论 BTree 还是 B+Tree,每个叶子节点到根节点距离都相同
  • BTree key 及 value 在每个节点上,无论叶子还是非叶子节点
image-20210901170943656
  • B+Tree 普通节点只存 key,叶子节点才存储 key 和 value,因此分叉数可以更多
    • 不过也请注意,普通节点上的 key 有的会与叶子节点的 key 重复
  • B+Tree 必须到达叶子节点才能找到 value
  • B+Tree 叶子节点用链表连接,可以方便范围查询及全表遍历
image-20210901170954328

注:这两张图都是仅画了 key,未画 value

B+Tree 新增 key

假设阶数(m)为5

  1. 若为空树,那么直接创建一个节点,插入 key 即可,此时这个叶子结点也是根结点。例如,插入 5

  2. 插入时,若当前结点 key 的个数小于阶数,则插入结束

Google Guava 文档

  1. 依次插入 8、10、15,按 key 大小升序

  2. 插入 16,这时到达了阶数限制,所以要进行分裂

  3. 叶子节点分裂规则:将这个叶子结点分裂成左右两个叶子结点,左叶子结点包含前 m/2 个(2个)记录,右结点包含剩下的记录,将中间的 key 进位到父结点中。注意:中间的 key 仍会保留在叶子节点一份

  4. 插入 17

  5. 插入 18,这时当前结点的 key 个数到达 5,进行分裂

  6. 分裂成两个结点,左结点 2 个记录,右结点 3 个记录,key 16 进位到父结点中

  7. 插入 19、20、21、22、6、9

  8. 插入 7,当前结点的 key 个数到达 5,需要分裂

  9. 分裂后 key 7 进入到父结点中,这时父节点 key 个数也到达 5

  10. 非叶子节点分裂规则:左子结点包含前 (m-1)/2 个 key,将中间的 key 进位到父结点中(不保留),右子节点包含剩余的 key

B+Tree 查询 key

以查询 15 为例

  • 第一次 I/O

Spring Boot 文档

  • 第二次 I/O

    image-20210901175738876

ActiveMQ 文档

  • 第三次 I/O

**B+Tree 删除叶


🚀✨ (未完待续)项目系列下一章

📚下一篇 将进入更精彩的环节! 🔔 记得收藏 & 关注,第一时间获取更新! 🍅 一起见证整个系列逐步成型的全过程。