十年大厂员工终明白:MySQL性能优化的尽头,是对B+树的极致理解

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 存储引擎是数据库的核心组件,负责数据的存储与管理。常见存储引擎如MySQL的InnoDB采用B+树结构,以优化读取性能,支持高效查询、范围检索和有序遍历。相比哈希表和B树,B+树通过减少I/O次数,提升大规模数据下的查询效率。本文深入解析B+树的原理、优势及其在MySQL中的应用。

存储引擎
存储引擎是数据库管理系统(DBMS)或键值存储系统的核心组件,它定义了数据在持久化存储介质上如何组织、存储、检索和管理。不同的存储引擎针对特定负载(如读密集型、写密集型、混合型)和数据模型(如关系型、键值型、文档型)进行优化。
目前常见的存储引擎使用的存储数据结构有如下几种。
1)哈希表(Hash Table):提供O(1)平均时间复杂度的单点查询(精确键匹配)。非常适合键值(Key-Value)存储,但天然不支持范围查询或有序遍历(除非对整个数据集扫描)。
2)B+树(Balance+ Tree):为磁盘I/O优化的多路平衡搜索树。广泛用于关系型数据库(如MySQL InnoDB, PostgreSQL)的索引和数据存储。支持高效的单点查询、范围查询和有序遍历。对读密集型和混合型负载友好。
3)LSM树(Log-Structured Merge Tree):专为高写入吞吐量设计的结构。通过将随机写转换为内存中的有序写入和磁盘上的顺序批量写入来优化写性能。广泛应用于写密集型的NoSQL数据库(如Google Bigtable, Apache HBase, Cassandra, RocksDB, LevelDB)。

MySQL B+树

image.png

MySQL的存储引擎,主要分InnoDB和MyISAM。InnoDB是MySQL的默认引擎,InnoDB使用B+树存储数据。表中的数据(主键索引)和辅助索引最终都会使用 B+ 树来存储,其中前者会以 的方式存储,而后者会以 的方式进行存储。

image.png

为了分析 InnoDB 选择 B+ 树作为其索引结构的原因,可以将其与 B 树和哈希表进行对比。随着互联网的快速发展,数据存储规模已攀升至千万甚至亿级,而典型的互联网应用场景往往是读多写少。例如,热点新闻的访问、商品列表的展示以及基于价格、地理位置等条件的智能化推荐排序,都需要高效的数据查询和排序能力。因此,数据存储结构需要满足以下核心需求。
1)高效的查询性能:尤其是在范围查询和排序操作上,需要具备优异的性能表现。
2)充分利用顺序 I/O 和 Page Cache 机制:通过优化 I/O 性能,减少磁盘访问的延迟。
3)支持大规模数据存储:在保证高效查询的同时,尽可能减少写入操作的 I/O 开销。

image.png

由于哈希映射关系,哈希表在查找单条数据时候,能保证O(1)的时间复杂读。但哈希表在范围查询和排序遍历时候,只能进行全表扫描并依次判断是否满足条件。全表扫描对数据库的性能影响非常大。比如如下的SQL语句:

SELECT * FROM commodity WHERE price > 10 AND price < 100
SELECT * FROM commodity WHERE ORDER BY price DESC

平均时间复杂度比O(1)稍慢的是O(logn),这类数据结构有平衡二叉树(AVL Tree),红黑树(RB Tree)、B树(B Tree)、B+树(B+ Tree)等。他们天然就支持排序、范围查找操作。

image.png

平衡二叉树在一般情况下查询性能非常好,但平衡二叉树单个节点只能保存一个数据,因此当覆盖大量数据时候,平衡二叉树的树高度很高。这意味着当需要通过遍历获取存储在硬盘上的数据时候,需要更多次的I/O操作。硬盘读取时间远远超过数据在内存中比较的时间,这将导致程序大部分时间会阻塞在硬盘 I/O 上。

B树
跟平衡二叉树的不同是,B树是一种多叉树。阶数m决定了B树的节点大小和树的高度。较大的阶数可以容纳更多的键值对,减少树的高度和硬盘访问次数。
B树中每个节点都存放着索引和数据,从下图可见,查询索引为 50 的节点就在第一层,B树只需一次硬盘 I/O 即可完成查找。因此B树的查询最好时间复杂度是 O(1)。

image.png

B+树
B+树是B树的一种变种,它与B树的区别是:
叶子节点保存了完整的索引和数据,而非叶子节点只保存索引值。所以查询索引为 50的数据,必须要遍历到叶子节点才能取到,因此查询时间固定为 O(logn)。
常见的B+树阶数可以是100或更大,以适应硬盘上的大量数据。

image.png

数据查询
B树的范围查询,比如上图要查询“大于10小于30的数据”,需要进行4次硬盘的随机 I/O 。范围查询的随机 I/O次数不稳定和放大,也是 B 树最大的性能问题:
1)遍历根节点的第一个元素是25,大于 10。
2)遍历左子节点的元素,找到第一个大于10的数据是11。
3)重新遍历根节点,发现不包含小于30的数据。
4)遍历载右子节点的元素,找到最后一个小于30的数据是27。
而B+树叶子节点保存指向下一个叶子节点的指针,叶子节点之间类似于单链表连接起来,因此叶子节点的数据在硬盘里是顺序存储的。当读到某个叶子节点数据时候,硬盘根据局部性原理会提前将相关的数据都读进内存,这使得范围查询和排序很高效。
操作系统在读文件时,根据Page Cache机制将数据加载到页缓存中,页的默认大小是4KB。由于B+树非叶子节点都只是索引值,这就意味B+树一次I/O,相比于B树能读出的索引值更多,从而减少查询时候需要的I/O次数。
不同于操作系统,InnoDB引擎的页大小默认是16KB,如下估算:
1)非叶子节点存放(key,pointer),假设主键ID为bigint类型,长度为8字节,而指针在InnoDB源码中为6字节,一共14字节,即非叶子节点能存放 16KB/14 左右的(key,pointer)。
2)叶子节点中保存的一行记录的数据大小为1KB,大约可以存储16K/1K = 16记录数。
如果B+树高度为2,那么存放总记录数为:根节点指针数单个叶子节点记录行数 = 16KB/14 16 大约 1.8w+ 数据。
如果B+树高度为3,那么存放总记录数为:根节点指针数单个叶子节点记录行数 = 16KB/14 16KB/14 * 16 大约2kw+数据。

数据写入
相比于数据读取场景,B+树在写密集型场景的性能并不理想。这主要原因是:B+树在写入(插入、删除、更新)时,为维持树的平衡,可能触发节点分裂、合并。这些操作可能涉及多个磁盘页的修改,导致随机I/O,且需要更新Page Cache中的对应页,使其失效。因此,在写密集型场景下,B+树性能不如专为写入优化的结构。

image.png

因此B+树也通过一些优化策略来提高写操作的性能。比如使用写缓冲区(Write Buffer)来缓存写操作,然后定期将缓冲区中的数据批量刷入硬盘,将随机I/O合并为后续的顺序I/O。此外可以使用多版本并发控制机制(MVCC)来减少写入时候的锁竞争和提高并发性能。

未完待续

很高兴与你相遇!如果你喜欢本文内容,记得关注哦!!!

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
6月前
|
存储 分布式计算 NoSQL
Facebook内部都在用的存储引擎,LSM凭什么能硬扛亿级写入流量?
RocksDB是Meta开源的高性能键值存储引擎,基于LSM树设计,专为高吞吐写入场景优化。其核心包括内存表MemTable、持久化SSTable、预写日志WAL及合并机制,适用于海量数据处理。
272 0
|
存储 算法 NoSQL
还分不清 Cookie、Session、Token、JWT?看这一篇就够了
Cookie、Session、Token 和 JWT(JSON Web Token)都是用于在网络应用中进行身份验证和状态管理的机制。虽然它们有一些相似之处,但在实际应用中有着不同的作用和特点,接下来就让我们一起看看吧,本文转载至http://juejin.im/post/5e055d9ef265da33997a42cc
49915 14
|
5月前
|
缓存 NoSQL 关系型数据库
MySQL 与 Redis 如何保证双写一致性?
我是小假 期待与你的下一次相遇 ~
618 7
|
8月前
|
消息中间件 缓存 监控
MQ消息积压 / Rocketmq 积压 最全的处理方案。 (秒懂+图解+史上最全)
MQ消息积压 / Rocketmq 积压 最全的处理方案。 (秒懂+图解+史上最全)
MQ消息积压 / Rocketmq 积压 最全的处理方案。 (秒懂+图解+史上最全)
|
缓存 安全 网络协议
HTTP和HTTPS的区别有哪些?
本文简要总结了 HTTP 和 HTTPS 的区别,从概念、端口、连接方式、使用场景、安全性等多个角度进行了对比。HTTP 是无状态的、无连接的应用层协议,适用于一般性网站和性能要求较高的应用;HTTPS 则通过 SSL/TLS 层提供加密、认证和完整性保护,适用于涉及敏感信息和高安全性的场景。文章还讨论了两者在性能上的差异,包括握手和加密开销、缓存效果以及 HTTP/2 的多路复用技术。最终,根据具体需求选择合适的协议能够更好地平衡安全性和性能。
17220 2
HTTP和HTTPS的区别有哪些?
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
Kubernetes API 调度
Kubernetes 架构解析:理解其核心组件
【8月更文第29天】Kubernetes(简称 K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用。它提供了一个可移植、可扩展的环境来运行分布式系统。本文将深入探讨 Kubernetes 的架构设计,包括其核心组件如何协同工作以实现这些功能。
1096 3
|
消息中间件 存储 负载均衡
2024消息队列“四大天王”:Rabbit、Rocket、Kafka、Pulsar巅峰对决
本文对比了 RabbitMQ、RocketMQ、Kafka 和 Pulsar 四种消息队列系统,涵盖架构、性能、可用性和适用场景。RabbitMQ 以灵活路由和可靠性著称;RocketMQ 支持高可用和顺序消息;Kafka 专为高吞吐量和低延迟设计;Pulsar 提供多租户支持和高可扩展性。性能方面,吞吐量从高到低依次为
5722 1

热门文章

最新文章