了解数据库中常用存储引擎数据结构(1)

news2024/11/27 11:54:02

目录

引言

存储引擎和存储结构

两者的关系

存储结构

分类

1. 按数据组织方式分类

2. 按索引结构分类

3. 按存储介质分类

4. 按数据分布方式分类

5. 按数据冗余和备份分类

存储结构需要的特性

BTree

补充知识:Lock和Latch的区别(存储引擎并发操作和事务并发操作的不同)

Latch导致的性能损失

BTree的各种变种

 LSM-Tree

补充知识:In-place和Out-of-place update方案差异


引言

数据库有三大模块:存储、事务、sql。

其中,存储模块负责数据在磁盘和内存上的存储、检索和管理,并向上层提供细粒度的数据操作接口。

因为存储和其他模块耦合较少,可以把它具象为一个专用的数据库组件,存储引擎。

存储引擎(Storage Engine)是数据库系统的组件,负责管理数据的物理存储和检索。在某些数据库系统中,存储引擎是可插拔的,这意味着可以选择或更换不同的存储引擎来适应不同的应用需求。存储引擎负责实际的数据存储、索引管理、事务支持、锁机制、崩溃恢复等底层操作。不同的存储引擎可能在这些方面有不同的实现方式,从而提供不同的性能和功能特性。

MySQL 是一个支持多种存储引擎的数据库系统。用户在创建表时,可以指定使用哪种存储引擎(如 InnoDB、MyISAM、Memory 等)。每个存储引擎都有自己的特点。

例如 InnoDB 支持事务和外键,
而 MyISAM 不支持事务但提供了更快的读操作。

根据应用场景的需求,用户可以选择最适合的存储引擎。

例如,
如果应用需要强事务支持和数据完整性保障,InnoDB 通常是首选;
如果需要高效的读操作和较少的写操作,并且不需要事务支持,MyISAM 可能更适合。

在 MySQL 中,一个数据库中的不同表可以使用不同的存储引擎。

例如,
一个数据库的用户表可以使用 InnoDB 存储引擎,以获得事务支持,
而日志表可以使用 MyISAM 存储引擎,以获得更高的写入性能。

对于存储而言,最重要的就是数据存储的结构(也即,数据结构!);

内存、缓存、读写流程的任何设计都是建立在存储结构的基础之上的!因此,存储结构和存储引擎的特性和性能关系非常密切!

存储引擎和存储结构

存储引擎和存储结构之间的关系可以类比为「软件」和「数据组织方式」的关系。存储引擎决定了数据的存储、检索、管理方式,而存储结构则是存储引擎在物理层面上实现这些功能所使用的具体数据组织形式。

存储引擎是数据库系统中负责管理数据存储和检索的核心组件,而存储结构则是存储引擎实现其功能的物理组织方式。存储引擎通过设计合理的存储结构来满足特定的性能要求和功能需求,两者密切关联,共同决定了数据库系统的数据管理效率和功能特性。

两者的关系

  • 存储引擎实现存储结构:存储引擎负责实现和操作存储结构。换句话说,存储引擎通过设计和管理存储结构来实现其功能。
    • 例如,InnoDB 存储引擎使用 B+ 树作为其索引结构,并使用数据页(通常为 16KB)作为基本的存储单位来管理表的数据。
  • 存储结构为存储引擎服务:存储结构的设计必须服务于存储引擎的功能需求。
    • 例如,InnoDB 的存储结构支持事务处理,因此它在存储结构中设计了事务日志(Redo Log 和 Undo Log)来支持事务的提交、回滚和崩溃恢复。
  • 灵活性与优化:存储引擎通过灵活的存储结构设计来优化特定的操作。
    • 例如,为了优化随机读写性能,存储引擎可能会使用聚簇索引(Clustered Index)将相关数据紧密存储在一起,减少磁盘的I/O操作。

存储结构

存储结构是指数据在物理存储介质(如磁盘、SSD)上的具体组织形式,用于支持数据库的高效存储、访问和管理。

分类

根据不同的应用需求和设计目标,存储结构可以分为多种类型。以下是存储结构的几种常见分类:

1. 按数据组织方式分类
  • 堆存储(Heap Storage)

    • 数据以无序的方式存储在表中,新插入的数据通常会被放置在表的末尾。
    • 优点:插入操作较快,不需要维护数据的顺序。
    • 缺点:数据检索速度较慢,通常需要全表扫描。
  • 有序存储(Ordered Storage)

    • 数据以某种顺序存储在表中,通常是按照一个或多个列进行排序。
    • 优点:对于顺序查询或范围查询速度较快。
    • 缺点:插入和删除操作较慢,需要维护数据的有序性。
  • 聚簇存储(Clustered Storage)

    • 数据按照主键或索引列的顺序存储,数据行与索引直接相关联。
    • 优点:索引查找更快,因为数据和索引在物理上相邻。
    • 缺点:插入、更新和删除操作可能较慢,因为需要维护数据和索引的顺序。
2. 按索引结构分类
  • B+树存储结构

    • 数据以 B+ 树的形式组织,常用于索引和快速数据检索。
    • 优点:支持快速的等值查询和范围查询,树的高度较低,查找效率高。
    • 缺点:插入和删除操作较复杂,可能需要调整树结构。
  • 哈希存储结构(Hash Storage)

    • 数据通过哈希函数映射到特定的存储位置,主要用于快速等值查询。
    • 优点:等值查询速度非常快。
    • 缺点:不适用于范围查询,哈希冲突可能导致性能下降。
  • 全文索引结构(Full-Text Indexing)

    • 专门为文本数据设计的索引结构,支持全文搜索。
    • 优点:适用于快速全文检索。
    • 缺点:创建和维护全文索引较为复杂,占用更多的存储空间。
3. 按存储介质分类
  • 磁盘存储结构

    • 数据存储在磁盘介质上,常见于传统数据库系统。
    • 优点:容量大,成本相对较低,数据持久化能力强。
    • 缺点:I/O 操作较慢,随机访问速度不如 SSD。
  • 内存存储结构(In-Memory Storage)

    • 数据存储在内存中,常用于内存数据库或缓存系统。
    • 优点:读写速度非常快,适合对延迟要求高的应用。
    • 缺点:容量有限,数据持久化能力较弱,断电后数据可能丢失。
  • 混合存储结构(Hybrid Storage)

    • 数据同时存储在内存和磁盘中,结合两者优点。
    • 优点:常用数据存储在内存中,提高访问速度,冷数据存储在磁盘中,降低成本。
    • 缺点:设计复杂,需要平衡内存和磁盘的使用。
4. 按数据分布方式分类
  • 行存储结构(Row-Oriented Storage)

    • 数据按照行进行存储,每一行数据存储在一起。
    • 优点:适合事务型应用(OLTP),对单行操作效率高。
    • 缺点:对于列操作(如分析型查询,OLAP)效率较低。
  • 列存储结构(Column-Oriented Storage)

    • 数据按照列进行存储,每一列数据存储在一起。
    • 优点:适合分析型应用(OLAP),对列操作效率高。
    • 缺点:对单行操作效率低。
  • 混合存储结构(Hybrid Storage)

    • 结合行存储和列存储的优点,常见于现代数据仓库系统。
    • 优点:兼顾事务型和分析型应用的需求。
    • 缺点:设计和实现较为复杂。
5. 按数据冗余和备份分类
  • 主从复制存储结构(Master-Slave Replication Storage)

    • 数据通过复制机制存储在主库和从库中,主库负责写入,从库负责读取。
    • 优点:提高读性能和数据可靠性。
    • 缺点:数据写入有延迟,从库数据可能滞后。
  • 分片存储结构(Sharding Storage)

    • 数据水平分割存储在多个节点或服务器上,每个节点存储部分数据。
    • 优点:支持大规模数据存储,提升写入和读取性能。
    • 缺点:查询复杂性增加,需要跨节点协调。

存储结构需要的特性

我们有那么多的数据结构,例如:数组、链表、Hash表等,为什么 BTree 或 LSM-Tree 能够作为存储结构呢?

存储结构的共性特点:

  • 适合磁盘存储(粒度一大),IO尽量少且一次读取连续的区域。
  • 允许并发操作(粒度一小),增删改对存储结构的影响尽量小。

根据上面两个特性再审视一下之前上面列出的内存数据结构不难发现:

  • 有1没2,即:只适合磁盘存储的,而不适合并发操作的:大文件、数组,他们都是一大段连续的存储区域,如果要修改,影响面很大,基本上要锁住整个数据结构!
  • 有2没1,即:高并发但是不适合磁盘存储的:链表、哈希表、二叉树、红黑树等,他们的修改、写入影响小,但数据结构的粒度也非常小,一般一次只操作几个字节,不适合磁盘 IO;

那么是否存在数据结构同时满足上面两个特性呢?当然,BTree 就是这么个数据结构。

BTree

B树是一个以页为单位组织的。

首先,InnoDB 存储引擎中页的大小为 16k,一般可以指出几百上千个指针,因而具有高扇出、低高度的特点,从而保证了 B树是连续 IO、并且 IO 次数极少,因此适合磁盘存储;

其次,B树要修改的单位也是页,因此并发控制的锁在页上,B树并发的程度也很高。

但是并非这么简单,虽然 B树要修改的单位是页,但是B树存在 SMO(Structure Modification Operation) 操作,导致B树的并发能力并不高。

SMO(Structure Modification Operation) 操作:在增删改操作可能会造成节点的分裂或者合并,此时需要操作多个磁盘块!

所以,如果我们想要保证出现 SMO 操作时读写安全的话,就需要对有可能受到 SMO 操作影响的一整条链上所有节点加锁,如下图所示: 

总之,虽然B树有一定的并发能力,但是由于 SMO 的存在使得B树的性能并不高,勉强满足并发要求,但是有很大的优化空间。

补充知识:Lock和Latch的区别(存储引擎并发操作和事务并发操作的不同)

这里补充一下存储引擎的并发操作和事务并发操作的不同。

假设都以锁机制来控制并发,上面两种机制对应的锁分别称为:Lock 和 Latch。

  • Lock:用来维持数据库事务的 ACID 特性,事务级隔离,锁住的对象为用户的数据,是一个逻辑概念,例如:共享锁、互斥锁(S、X锁)等;
  • Latch:保护数据读取过程中,加载到内存中数据结构的锁,是线程级隔离的锁;主要是防止多个线程并发去修改内存中的共享数据;

例如,假设修改一行数据,那么首先需要将这行数据所在的页加载至内存中,随后进行修改。

而在修改前,为了防止其他线程也要来修改这页数据,需要使用 Latch 对内存数据进行上锁;加好 Latch 后,可以对数据进行修改。

此时,为了防止在事务进行提交之前,存在其他别的事务读到这行修改后未提交的数据,此时需要对数据增加 Lock。

虽然 Latch 锁掉整个页数据,而 Lock 仅仅锁掉单行数据; 但是一旦完成了对这行数据的修改,那么 Latch 锁就可以释放,而 Lock 锁需要等到整个事务提交之后才能够释放! 在数据修改完成到事务提交的这段时间,Lock 就可以发挥作用了!

因此,在对数据库进行操作时,实际上是存在 Latch 和 Lock 两种锁共同生效的!但是对于用户而言,只能感觉到 Lock 锁(事务锁);

Latch导致的性能损失

虽然 Latch 的持续时间很短,但是他也会严重影响数据库性能!

BTree的各种变种

刚讲了上面的内容,那么 BTree 的各种变种的优化方向大致也就是通过优化下面两个方向来设计的:

  • 1、适合磁盘存储(提高粒度),IO 尽量少且一次读取连续的区域;
  • 2、允许并发操作(减小粒度),增删改对存储结构的影响尽量小;

例如,最出名的 B+Tree 在非叶子节点中仅保留指针(在 BTree 中非叶子结点也存储了行数据),所有的数据都存放在叶子节点,间接减少了树的高度。

并且这样还可以区分开索引段和数据段,有助于全表扫描时的顺序IO。总之,提升了 BTree 的特性1。

而 B-Link Tree 对 BTree 的并发控制机制做了很大的改进,提升了特性2。

对于近些年才提出的 Bw-Tree 而言,其采用了类似于 LSM-Tree 的 out-of-place update 方法,追加的写入完全无 Latch 操作(避免多线程并发写),从更根本的角度上提升了特性2。

 LSM-Tree

LSM-Tree整体是一个分为多层、并且越向下层数据越多的层次树形结构;

对于写操作:

  • 所有的写入操作都会首先直接写入内存(write),如果内存写满了,就会直接将内存中刚刚写入的这块数据刷入磁盘中(flush)。
  • 当向磁盘刷入一定数量的数据之后,将本层数据和下一层数据进行合并、排序、去重。整理后的数据就放在下一层,因此就去除了数据的冗余(compaction)。
  • Compaction 过程可能会持续多层,并且越下层的数据就越多,最终就形成了 LST-Tree 的整体结构。

读取的时候需要注意:由于一个 key 对应的 value 可能会存在于多个层次上,此时需要以最新(更上层的)数据为准。因此,在查询时需要从上至下一层层的搜索,而第一条找到的就是我们要读的结果!

由于其 Out-of-place 的特点:所以在正常插入到内存时,完全不会改变历史数据的结构,即:没有 SMO 过程。因此,并发能力很强,BTree 在特性2上的瓶颈在 LSM-Tree 中不存在。

而 LSM-Tree 中每层数据都比较多,在缓冲池没有命中时,读取 LSM-Tree 时读取的次数可能会非常多!所以,LSM-Tree 在特性1上的表现并不好!

但是,可以优化 LSM-Tree 的特性1,下面是几个常用的优化手段:

  • 依靠 Compaction 操作整理 LSM-Tree 的结构,减少读 IO 的次数;
  • 使用 Bloom Filter 对数据进行过滤;

实际上 Compaction 操作就可以看作为 LSM-Tree 的 SMO 操作!在 Compaction 期间,不仅会占用大量资源,并且还会造成缓冲丢失、写停顿(write stall)等问题,减少并发能力。因此,对 LSM-Tree 优化的关键点就落在 Compaction 操作上。

补充知识:In-place和Out-of-place update方案差异

对于 In-place update 结构而言,需要把磁盘中的结构加载到内存中,再修改并写回至磁盘中,因此免不了要使用 Latch 机制来做并发控制。

而对于 Out-of-place update 结构而言,虽然存在其他因素干扰其并发能力,但是由于所有的写入都是追加操作,因此无需采用基于 Latch 的机制进行并发控制。

由于现在多核处理器的发展,NUMA 模式逐渐成为主流,多核处理器在面对 Latch 的频繁获取和释放时都会损耗很多性能。

可以简单理解为,CPU 中每个核都有独立的一块存储区域,而读取或者写入的过程就需要将页数据加载到这块存储区域中。这样,并发读写时,一些节点就可能会存在多个核空间中。而加 Latch 和解 Latch 的操作又必须同步给多个核,这就造成了很大的性能损耗。

最显著的例子,对于 B+Tree 而言,在读写时由于根节点是必经之路,因此频繁的对根节点加解 Latch 就会极大的影响多核场景下的并发性能!

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

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

相关文章

干货分享|如何使用Stable Diffusion快速打造瞬息全宇宙?

Deforum也是一款文生视频插件,它把提示词跃迁和运镜结合到一起,生成的视频让人仿佛穿越不同时空,因此又被称作瞬息全宇宙。本节将介绍使用Deforum生成视频的方法。 在使用Deforum时,由于设置参数非常多,初次使用时很难…

【C语言篇】编译和链接以及预处理介绍(下篇)

文章目录 前言#和###运算符##运算符 命名约定#undef命令⾏定义条件编译#if和#endif多个分支的条件编译判断是否被定义嵌套指令 头文件被包含头文件被包含的方式本地文件包含库文件的包含 嵌套文件包含 其他预处理指令 写在最后 前言 本篇接前一篇【C语言篇】编译和链接以及预处…

fvm 管理多个 flutter 版本

前言: flutter SDK 版本更新还是比较快的,新的特性带来了新的体验,更新频繁也是好的事情。一方面说明 flutter 社区活跃,另一方面 说明 flutter 进化的脚本并没有停下。这样也会带来另一个问题,如果多个项目 使用了不…

详解Python 66 个内置函数!附代码

大家好,想掌握Python编程语言,从零基础的小白晋升为大神?没问题!接下来我们将以轻松有趣的方式,逐一解锁Python的66个内置函数,每一步都将结合实际应用场景、函数功能解析及简洁代码演示,带你深…

超全面!Midjourney用户手册中文版!详解模型、命令、参数与高级用法

前言 引言 大家好,我是包大。 最近正在上手体验目前网上很火的 AI 绘画工具 Midjourney,在优设和 B 站上找了很多教程来看,现在基本可以上手用它生成很多好玩的图片了。 这里私心推荐一下优设网的 AI 绘画专题,专题里已经积累了…

Docker详细讲解

2013年发布至今, Docker一直广受瞩目,被认为可能会改变软件行业。 但是,许多人并不清楚 Docker 到底是什么,要解决什么问题,好处又在哪里?今天就来详细解释,帮助大家理解它,还带有简…

【Linux操作系统】进程概念

目录 一、进程概念1.1 什么是进程 二、task_struct内容分类2.1 标识符2.2 进程状态2.2.1 进程排队2.2.2 关于进程状态的表述——运行、阻塞、挂起2.2.3 Linux中具体的进程状态2.2.4 孤儿进程 2.3 进程优先级 三、Linux的调度与切换3.1 进程切换3.2 进程调度 四、环境变量4.1 ma…

产品文档全攻略:分类、价值及创建技巧

作者 | Josh Fechter 产品文档是产品附带的资料。这些文档包含产品工作的详细信息、使用指南、免责声明以及与产品相关的其他重要详细信息。 产品文档是一个广义的术语,并不仅仅是为了供消费者使用。产品文档还包括供内部组织使用的产品或服务的信息。这些文档文件…

KETTLE调用http传输中文参数的问题

场景:检查服务器异常(hive)服务,就通过http发送一条短信到手机上,内容类似:【通知】 S T A R T D A T E h i v e 服务检测异常 {START_DATE}_hive服务检测异常 STARTD​ATEh​ive服务检测异常{DB_ID}&#…

我的点赞功能(完整分页查询步骤)和快速刷题开发

文章目录 1.我的点赞分页展示1.分页查询工具类1.PageInfo.java 需要分页查询的就继承它,传值的时候pageNo和pageSize可以为空2.PageResult.java 根据条件从数据库中查询信息,然后设置这里的四个值即可得到分页查询结果 2.sun-club-application-controlle…

记一次Nginx代理配置的奇怪经历

目录 1 背景 2 需求 3 方案 4 问题 5 解决方案 6 最后记录 7 参考文献 1 背景 最近我们在做一个能源类智能化转型的项目,整个项目非常大,下面有很多的子项目组。不同项目组之间都是独立的子系统。 客户对技术上做了统一要求,使用统一的…

SpringBoot 自动配置(Condition)

一.Condition Condition 是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操 作。 案例:需求1 在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求: 1. 导入Jedis坐标后,加载该Bean…

基于STM32开发的智能农业灌溉系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码控制代码应用场景 农田自动化灌溉家庭园艺智能浇灌常见问题及解决方案 常见问题解决方案结论 1. 引言 智能农业灌溉系统通过集成多种传感器,实时监测土壤湿度、温度、…

​【迅为电子】RK3568驱动指南|第十七篇 串口-第196章 串口简介

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

项目视图组(基于模型)Model-Based-Qt-思维导图-学习笔记

项目视图组(基于模型)Model-Based Model-Based (1)List View:清单视图 QListView 继承关系:继承自 QAbstractItemView,被 QListWidget 和 QUndoView 继承 功能:提供模型上的列表或图标视图,以非分层列表…

通过连接数据库演示解耦过程

一、什么是解耦? 解耦就是为了降低程序之间的耦合性,在软件工程中,对象之间的耦合度就是对象之间的关联度。程序之间耦合度越高,程序维护起来也就越困难,即程序维护成本高。所以我们需要通过现有方法降低耦合性&#x…

oss学习问题记录

1.在使用oss上传文档时,根据返回的地址访问上传的图片,会报错误如下:This XML file does not appear to have any style information associated with it. The document tree is shown below. 在设置了上传的文档类型和代码设置读写权限之后 …

Redis的基本概念和使用

目录 一、Redis简介 1、NOSQL 2、NOSQL和关系型数据库比较 3、主流的NOSQL产品 4、什么是Redis 5、启动Redis 二、Redis基本操作 1、大概操作 三、 Redis 数据类型(5种常用) 1、redis 数据存储格式 2、String 3、hash 4、list 5、Set 6、…

面试题-Spring Bean的生命周期

文章目录 Spring Bean 生命周期分为哪几个阶段浅析Bean生命周期源码实现1.1 DefaultListableBeanFactory1.2 createBean2.1 populateBean3.1 initializeBean3.2 invokeInitMethod3.3 applyBeanPostProcessorsBeforeInitialization5.1 destroyBean5.2 invokeDestroyMethod Sprin…

Python爬虫——爬取某网站的视频

爬取视频 本次爬取,还是运用的是requests方法 首先进入bilibili官网中,选取你想要爬取的视频,进入视频播放页面,按F12,将网络中的名称栏向上拉找到第一个并点击,可以在标头中,找到后续我们想要…