数据库存储引擎是数据库管理系统(DBMS)中用于存储、检索和管理数据的核心组件。它是数据库底层实现的一部分,负责处理数据的物理存储和逻辑结构,以及提供对数据的高效访问。不同的存储引擎具有不同的特性、优势和限制,适用于不同的应用场景。
存储引擎的主要职责包括:
数据存储:定义数据如何存储在磁盘上,包括数据的格式、压缩方法、索引方式等。不同的存储引擎可能会采用不同的数据结构(如B树、哈希表、日志结构合并树等)来优化数据的存储和访问。
事务处理:支持事务的ACID(原子性、一致性、隔离性、持久性)特性,确保数据的完整性和一致性。存储引擎需要实现适当的事务管理机制,以处理并发事务、锁定机制、事务日志等。
索引支持:提供索引机制以加速数据的检索。索引是数据库中一种特殊的数据结构,可以大大提高查询效率。不同的存储引擎可能会支持不同类型的索引(如B树索引、哈希索引、全文索引等)。
并发控制:处理多个用户或进程同时访问数据库时的并发问题。存储引擎需要实现适当的并发控制机制,如锁定机制、多版本并发控制(MVCC)等,以确保数据的一致性和完整性。
查询优化:优化查询的执行计划,以提高查询性能。存储引擎可以根据数据的统计信息、索引结构等,选择最优的查询路径和算法。
备份与恢复:提供数据备份和恢复的功能。存储引擎需要支持数据的导出、导入、备份和恢复操作,以确保数据的安全性和可靠性。
行存与列存
首先介绍两者在磁盘中的存储形式,比如下面表格:
id | name | age |
1 | 张三 | 32 |
2 | 李四 | 22 |
3 | 王五 | 42 |
4 | 赵六 | 52 |
行存在磁盘的中存储形式:1 张三 32,2 李四22,3 王五 42,5 赵六 52
列存在磁盘中的存储形式:1234,张三 李四 王五 赵六,32 22 42 52
相关链接:行存储 VS 列存储[通俗易懂]-腾讯云开发者社区-腾讯云
行存
在行式存储中,一条记录(即一行数据)被存储在一块连续的物理空间中,而整张表的所有记录按照一定的顺序依次存放。这种存储方式的优点如下:
- 顺序访问:由于行式存储按照记录的顺序进行存储,因此可以快速地访问特定的记录,即通过主键或索引进行查询。
- 事务处理优势:由于行式存储按照记录的顺序进行存储,因此在执行事务处理(如增删改查操作)时,行式存储能够更好地支持并发控制和恢复机制。
缺点:
- 空间浪费:如果某些行的某些列没有值,那么这些位置将会被占用,造成空间浪费。
- 无法轻易利用数据压缩:由于行式存储是按照记录的顺序进行存储的,因此无法简单地利用数据压缩技术来减少存储空间。
- 全表扫描性能较低:在查询时,如果需要通过全表扫描来查找满足某些条件的数据,那么将会带来较大的性能开销。
列存
按照列进行存储的一种方式。在列式存储中,同一列的所有数据都被存储在一起,而不同列的数据则被分开存储。这种存储方式的优点如下:
- 数据压缩:由于列式存储将同一列的数据存储在一起,因此可以使用更高效的数据压缩算法来减少存储空间。例如,如果某一列的数据类型都是相同的(如全部为数字),那么可以使用位图索引等技术来进行压缩。
- 查询优化:在列式存储中,数据是按照列进行组织的,因此在查询时可以更快地定位到满足条件的数据。此外,列式存储也支持更高级的索引技术(如位图索引、B树索引等),进一步提高了查询性能。
- 分页和缓存友好:列式存储在分页和缓存方面也表现出较好的性能。由于同一页或缓存块中的数据是同一列的,因此可以减少I/O操作次数。
缺点:
- 访问特定行较慢:在列式存储中,数据是按照列进行组织的,因此在访问特定的行数据时需要更多的I/O操作。
- 事务处理劣势:由于列式存储的数据是分开的,因此在执行事务处理(如增删改查操作)时需要更多的锁资源,可能影响并发性能。
- 数据复制和备份困难:在列式存储中,每一列数据都是相互关联的,因此在进行数据复制和备份时需要更多的时间和资源。
综上所述,数据库系统将数据分为行式存储和列式存储是为了更好地满足不同的应用场景和需求。行式存储适合于对记录完整性要求较高的事务处理和完整性约束场景;而列式存储则更适合于对查询性能要求较高的数据分析的场景。在实际应用中,用户可以根据具体的需求选择合适的存储方式。
磁盘存储引擎
Ustore
Ustore(原地更新in-place update):数据的更新是直接作用于存储中的现有数据的,即直接修改原有记录。是openGauss内核新增的一种存储模式。其多版本的实现较Astore最大的区别在于最新版本和历史版本的数据是分离存储的。
适用场景:频繁更新和需要实时展示最新数据的场景。
Ustore页面中仅存储最新的版本数据,旧版本的数据会被集中存储在undo空间中。
相关链接:openGauss数据库源码解析系列文章——存储引擎源码解析(四)_csn源码-CSDN博客
Astore
astore(追加存储Append store):每当有新的数据需要写入时,它们会被追加到现有数据的末尾,而不是覆盖旧的数据。
Astore与Ustore的多版本实现最大的区别在于最新版本和历史版本是否分离存储。Astore不进行分离存储,而Ustore当前也只是分离了数据,索引本身没有分开。
使用Astore的优势
- Astore没有回滚段,而Ustore有回滚段。对于Ustore来说,回滚段是非常重要的,回滚段损坏,会导致数据丢失甚至数据库无法启动的严重问题;且Ustore恢复时同步需要Redo和Undo。由于Astore没有回滚段,旧数据都是记录在原先的文件中,所以当数据库异常crash后,恢复时,不会像Ustore数据库那样进行那么复杂的恢复。
- 由于旧的数据是直接记录在数据文件中,而不是回滚段中,所以不会经常报Snapshot Too Old错误。
- 回滚可以很快完成,因为回滚并不删除数据,但回滚时很复杂,在事务回滚时必须清理该事务所进行的修改,插入的记录要删除,更新的记录要更新回来,同时回滚的过程也会再次产生大量的Redo日志。
- WAL日志要简单一些,仅需要记录数据文件的变化,不需要记录回滚段的变化。
Cstore
Cstore(列存储Column Store):将数据按列而不是按行进行存储的模型。cstore列存储的主体数据文件以CU为I/O最小单元,只支持追加写操作。
astore,ustore,cstore对比
特性 | Astore (Append Update) | Ustore(原地更新in-place update) | Cstore (Column Store) |
数据存储方式 | 行存 | 行存 | 列存 |
数据更新方式 | 追加更新(数据以追加方式写入,不覆盖旧数据) | 原地更新(直接更新现有数据,减少冗余) | 列存储,非原地更新 |
适用场景 | 写入密集型,需要永久保存历史记录的场景。比如:日志记录系统 | 频繁更新和需要实时展示最新数据的场景。比如:实时在线交易系统(OLTP),用户信息管理系统 | 数据分析,OLAP,大数据分析平台 |
适合工作负载 | 写多读少,如日志记录 | 写多读多,,更新频繁 | 读多写少,如数据仓库 |