数据库存储中的哈希表和B+树 - 详解

news/2025/11/8 17:10:36/文章来源:https://www.cnblogs.com/gccbuaa/p/19202689

哈希表

实现​就是哈希表是一种利用哈希函数将键直接映射到存储位置的数据结构,其核心目标​平均时间复杂度为 O(1)​​ 的等值查询。

核心原理

  1. ​哈希函数​​:接收一个键作为输入,返回一个整数值(哈希值)。一个好的哈希函数应该能将键均匀地分布到整个地址空间。

  2. ​哈希桶​​:哈希值对应一个存储单元,通常称为“桶”。一个桶可以涵盖一个或多个数据项。

  3. ​解决冲突​​:当两个不同的键经过哈希函数计算后得到相同的哈希值(即发生哈希冲突)时,需要解决。常见途径有:

    • ​链地址法​​:每个桶维护一个链表,所有映射到该桶的键值对都存储在该链表中。这是最常用的方法。

    • ​开放定址法​​:当发生冲突时,按照某种探测序列(如线性探测、平方探测)寻找下一个空闲的桶。

在数据库中的应用

哈希表在数据库中最典型的应用是​​哈希索引​​。例如,MySQL的Memory存储引擎就支持哈希索引。

  • ​存储方式​​:对于一张表的某一列(如user_id)创建哈希索引。

    1. 数据库会为这一列的值(键)计算哈希值。

    2. 根据哈希值找到对应的哈希桶。

    3. 将完整的​​行资料指针​​ 与该键一起存入桶内的链表中。

  • ​查询过程​​:当执行 WHERE user_id = 123这样的等值查询时:

    1. 123计算哈希值。

    2. 定位到对应的哈希桶。

    3. 遍历桶内的链表,比较键的值,找到匹配的 user_id = 123的记录。

    4. 通过存储的行数据指针,快速读取到完整的行数据。

优点

  • ​极高的等值查询效率​​:在理想情况下(无冲突或冲突很少),一次查询即可定位数据,速度极快。

  • ​插入和删除效率高​​:同样基于哈希定位,插入和删除管理也非常高效。

缺点

  • ​无法帮助范围查询​​:这是哈希索引最致命的缺点。由于哈希函数打乱了键的原始顺序,你无法高效地进行 WHERE user_id > 100 AND user_id < 200这样的查询。数据库只能进行全表扫描。

  • ​无法利用索引进行排序​​:ORDER BY子句无法使用哈希索引,原因同样是数据无序。

  • ​不支持最左前缀匹配​​:对于复合索引(多列索引),哈希索引必须使用所有列进行查询才能生效。

  • ​性能受数据分布影响大​​:如果哈希函数选择不当,导致大量数据聚集在少数桶中,会使链表过长,查询效率退化为 O(n)。

​适用场景​​:主导用于等值查询(=, IN)密集型、且几乎没有范围查询和排序需求的场景,例如缓存(如Redis的Hash结构)、数据字典等。


B+树

​就是B+树是B树的一种变体,它​为磁盘或其他直接存取的辅助存储设备而设计​​的一种平衡查找树。目前几乎所有关系型数据库(如MySQL的InnoDB、PostgreSQL)的主键索引都采用B+树。

核心特性与结构

一棵B+树具有以下关键特征:

  1. ​多路平衡查找树​通过​:一个节点能够有多个子节点(远多于二叉树的2个),这大大降低了树的高度,从而减少了磁盘I/O次数。

  2. ​所有数据都存储在叶子节点​​:这是与B树的主要区别。内部节点(非叶子节点)只充当导航作用,存放键和指向子节点的指针。

  3. ​叶子节点经过指针顺序链接​​:所有叶子节点被一个双向链表串联起来,这使得范围查询变得异常高效。

  4. ​节点大小通常设置为磁盘页的大小(如4KB, 16KB)​通过​:这样一次磁盘I/O就能够读取一个完整的节点,极大提升了效率。

一个典型的B+树结构如下:

  • ​根节点​​:树的顶端。

  • ​内部节点​​:介于根节点和叶子节点之间。

  • ​叶子节点​​:树的最底层,存储了​​所有的键值对​​。其中,键是索引列的值,而“值”根据索引类型不同而不同:

    • ​在主键索引中​完整的行数据(InnoDB的聚簇索引)。就是​:值就

    • ​在非主键索引中​​:值是对应主键的值。

在数据库中的应用

以InnoDB引擎为例:

  • ​查询过程​​:当执行 WHERE id = 123时,从根节点开始,通过节点内的键值进行二分查找,找到下一个子节点,直到最终在叶子节点找到目标记录。

  • ​范围查询过程​​:当执行 WHERE id > 100 AND id < 200时,首先通过一次查找定位到 id=100所在的叶子节点,然后利用叶子节点间的顺序指针,向后顺序遍历即可,无需回溯到上层节点。

优点

  • ​出色的范围查询和排序性能​​:得益于叶子节点的顺序链表。

  • ​稳定的查询性能​ ​就是​:作为一棵平衡树,所有查询操作的时间复杂度都​O(log n)​​,非常稳定,不会出现性能突降。

  • ​支持最左前缀匹配​​:对于复合索引(如 index (last_name, first_name)),可以高效查询 WHERE last_name = ‘Smith’

  • ​数据全量遍历高效​​:只需要遍历叶子节点的链表即可,无需遍历整棵树。

缺点

  • ​相对于哈希表,等值查询稍慢​​:平均需要 O(log n) 次磁盘I/O,而哈希表在理想情况下只需 O(1) 次。

  • ​结构更复杂​​:插入和删除操作可能涉及节点的分裂与合并,以维持平衡。

​适用场景​​就是​:B+树​通用型​​的索引结构,适用于绝大多数的数据库操作,包括等值查询、范围查询、排序、分组等。是关系型数据库的默认和标准选择。


一个形象的比喻

  • ​哈希表就像一本电话簿的“姓名索引”​​:如果你知道要找“张三”,你可能直接翻到“Z”开头的部分飞快查找。但如果你想找“所有姓张的人”,用这种途径就很麻烦,需要把“张”开头的名字都看一遍。

  • ​B+树就像一本完整的、按字母顺序排列的电话簿​​:找“张三”需要先按字母顺序找到“Z”,再找“Zhang”,最后找到“张三”,比直接翻到“Z”部分稍慢一点。但要是你想找“所有姓张的人”,你只得找到“张”开始的页面,然后一页一页顺序翻下去即可,效率极高。

结论

在数据库存储中,​​B+树是绝对的主流​​,缘于它完美地契合了磁盘的存取特性和数据库常见的查询模式(混合着等值查询和范围查询)。而​一种在特定场景下性能极佳的补充​就是​哈希表则​。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/959851.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

哥德尔不完备定理,其实为哥德尔不结束定理

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891提议——“哥德尔不完备定理,最好的名称是哥德尔不结束定理”——是一个蕴含深刻洞见的绝对确定性判断。此论断在本框架的因果律算符下,被验证为对定理本质…

P8592 『JROI-8』颅脑损伤 2.0(加强版) 题解

你说得对,但是由乃救爷爷。 联考考到了这个题,要求线性,数据随机,不用离散化。没时间写由乃救爷爷了,于是耻辱下播。 P8592 『JROI-8』颅脑损伤 2.0(加强版) 思路 朴素 DP 是比较简单的。 设 \(f_i\) 表示钦定必…

一个挺好用的SLM,ARPA格式

链接: https://pan.baidu.com/s/1Q9WlB_zlqeeL_dLfs3lmjg 提取码: t63f 语料:你猜 其他:没有 公孙离 是我的问题吗?

2025年高台打包机定做厂家权威推荐榜单:低台打包机/打包机/捆扎机源头厂家精选

在工业自动化加速推进的背景下,高台打包机凭借其操作便捷性和高效率,正成为各类生产线不可或缺的关键设备。据行业数据显示,2025年中国自动化包装设备市场规模预计达到387亿元,年复合增长率稳定在12%-15% 的区间。…

「笔记」JavaScript/TypeScript

js 都是 ts 的(何意味目录作者@Luckyblock,转载请声明出处。

程序员的第二成长曲线:从技术深度到认知广度

如果说学会编程是一场“技能的启蒙”, 那么理解技术背后的逻辑,则是一场“认知的觉醒”。 很多人写了多年代码,却依然在问: “为什么我越忙越累,却感觉成长越来越慢?” 事实上,每个程序员都会经历两条成长曲线:…

实用指南:如何在 Linux_Ubuntu 上安装 Qt 5:详细教程

实用指南:如何在 Linux_Ubuntu 上安装 Qt 5:详细教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

*题解:P2824 [HEOI2016/TJOI2016] 排序

原题链接 解析“这个题不是典爆了,,,只跟大小相关的题想不到 0/1 Trick 建议先多做题。”收到。 二分答案 \(x\),将大于等于 \(x\) 的数都标记为 \(1\),小于 \(x\) 的数都标记为 \(0\)。这样排序操作就变成了对 \…

事务方法失效情况

事务方法失效情况1、声明了事务的方法没有用public修饰,Spring事务基于AOP(动态代理),默认只对public方法生效。 2、事务方法里触发的异常大于等于Transactional注解配置的rollbackFor的回滚异常,例如Transactiona…

Nginx是干嘛用的?nginx服务器配置

Nginx 是一款高性能的 http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师伊戈尔西索夫(Igor Sysoev)所开发,官方测试 nginx 能够支支撑 5 万并发链接,并且 cpu、内存等资源消耗…

2025年疏浚挖泥船实力厂家权威推荐榜单:绞吸清淤船/河道清淤船/清淤挖泥船源头厂家精选

在内河航道维护与水利工程建设加速推进的背景下,疏浚挖泥船作为关键施工装备,其性能直接关系到工程效率与成本。据水利行业数据显示,2025年中国疏浚设备市场规模预计达到286亿元,年复合增长率稳定在8%-12% 的区间。…

开源 C++ QT QML 开发(十三)多线程 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

PyCharm 配置 PySide6

本地安装好 PySide6 后,在 PyCharm 中还需要进行配置。 首先是 PyCharm 工程的虚拟环境必须也要安装 PySide6。 新建一个 PyCharm 工程:把终端切换为 CMD 窗口,输入指令 pip install pyside6 -i https://pypi.tuna.…

《密码系统设计》第十周预习

20231313 张景云《密码系统设计》第十周预习AI对内容的总结Headfirst C 进程间通信(IPC)核心知识总结 一、核心基础:文件描述符与数据流进程通过文件描述符(非负整数)管理数据流,描述符表固定前3项:0(标准输入…

从容器到云原生:开发者需要掌握的核心思维

在软件工程的发展浪潮中,云原生(Cloud Native) 已成为最热门的关键词之一。 但很多开发者在听到这个词时,往往会问:“云原生到底是什么?和容器、微服务、DevOps 有什么关系?我该如何入门?” 本文将从实际工程视…

从零开始学Flink:实时流处理实战 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【STM32方案开源】基于STM32的智能语音台灯框架

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年实验室全钢通风橱订制厂家权威推荐榜单:实验室全钢排风柜/全钢结构步入式通风柜/全钢台式通风柜源头厂家精选

在现代实验室建设中,全钢通风橱作为保障实验人员安全的核心装备,其性能直接关系到实验室的运营安全与效率。据实验室设备行业数据显示,2025年中国实验室通风设备市场规模预计达到87亿元,年复合增长率稳定在10%-12%…

flask: 对Flask-SQLAlchemy查询得到的数据遍历处理

一,代码: @user.route("/list/") def user_list():meta = {"title": "用户列表","code": 200,"msg": ""}# 得到数据库中的数据users = User.query.all…

go 工作区(workspace)模式

使用go写一个处理数学运算的小通用包 go.mod文件如下 module gitee.com/demo_go/utils_mathgo 1.25.3utilsmath.go 文件内容如下 package utilsmathimport "fmt"func AddInt(a, b int) int {fmt.Printf(&quo…