页
在 PostgreSQL 中,一个页(page)是数据库存储的基本单位。它是一个固定大小的数据块,用于存储数据库的数据和索引。
以下是有关 PostgreSQL 中页的一些重要信息:
-
大小:在 PostgreSQL 中,页的默认大小是 8KB。这是最常用的页大小,但 PostgreSQL 也支持其他大小的页,如 4KB、16KB、32KB 等。页的大小在数据库创建时被指定,通常无法更改。
-
存储数据:每个页用于存储数据库的数据。数据表的行(记录)存储在页中,包括列的实际数据和元数据。每个页通常可以容纳多行数据,具体取决于行的大小以及页的大小。
-
索引:除了存储数据,页还用于存储数据库的索引。索引是帮助快速定位和检索数据的数据结构。不同类型的索引(如 B-tree、哈希索引等)使用页来组织和存储索引数据。
-
数据文件:数据库的数据存储在物理的数据文件中。每个数据文件由多个页组成,这些页按顺序存储在文件中。文件系统管理这些数据文件的创建、扩展和管理。
-
页的读写:当数据库需要读取或写入数据时,它会按照页的粒度进行操作。数据库会将整个页从磁盘读取到内存中进行处理,并在需要时将修改后的页写回磁盘。
-
脏页:在数据库中,当一个页被修改但尚未写回磁盘时,称为 “脏页”(dirty page)。脏页表示该页的内容与磁盘上的数据不一致。在适当的时机,脏页将被刷新到磁盘,以确保数据的持久性和一致性。
页是 PostgreSQL 中数据存储和管理的基本单位。它用于存储表数据和索引,并在数据库读写操作中起着重要的角色。理解页的概念对于理解数据库的存储结构和内部工作原理非常重要。
除了页(page),在 PostgreSQL 中还有一些其他重要的概念和组件,这些组件一起构成了数据库的存储结构和运行机制。以下是一些与页相关的概念和其他重要组件:
-
行(Row):行是数据库中的基本数据单元。它代表了数据表中的一条记录,包含了表的列和对应的数据值。每个页可以容纳多行数据。
-
数据文件(Data File):数据文件是数据库中存储数据的物理文件。它由多个页组成,每个数据文件都包含了一部分数据表的数据。数据文件由文件系统管理,数据库引擎负责管理和操作这些文件。
-
表空间(Tablespace):表空间是逻辑上的存储单位,它包含了一个或多个数据文件。每个表空间都属于一个特定的数据库,并用于存储该数据库的表、索引和其他数据库对象。
-
目录(Directory):目录是用于管理和组织数据库对象的逻辑结构。它包含了表、索引、视图、函数等数据库对象的定义信息。目录中的每个对象都与一个或多个数据文件中的页相关联。
-
日志(Log):日志是用于记录数据库操作的文件。在 PostgreSQL 中,有两种类型的日志:事务日志(Transaction Log)和归档日志(Archive Log)。事务日志记录了对数据库的修改操作,而归档日志用于备份和恢复数据库。
-
缓冲池(Buffer Pool):缓冲池是用于缓存数据库中的页的内存区域。它存储了最近被访问的页,以提高数据库的读取性能。当需要读取或写入页时,数据库引擎首先检查缓冲池中是否存在相应的页,如果存在,则直接从缓冲池中读取或写入数据,避免频繁访问磁盘。
-
WAL(Write-Ahead Logging):WAL 是 PostgreSQL 中的一种日志记录机制。它确保在对数据库进行修改之前,相关的日志记录已经写入磁盘。WAL 可以用于恢复数据库的一致性,并提供了数据持久性的保证。
这些概念和组件共同构成了 PostgreSQL 的存储结构和运行机制。了解这些概念可以帮助理解数据库的内部工作原理和性能优化技术。
存储结构
PostgreSQL 数据库的存储结构由多个组件组成,这些组件协同工作来存储和管理数据。下面是 PostgreSQL 数据库的主要存储结构组件:
-
数据文件(Data Files):
- 数据文件是物理上存储数据库数据的文件。每个数据库可以由一个或多个数据文件组成。
- 数据文件存储着表、索引和其他数据库对象的数据。
- 数据文件由文件系统管理,可以根据需求进行创建、增长和缩小。
-
表空间(Tablespaces):
- 表空间是逻辑上组织数据文件的容器。
- 每个数据库可以有一个或多个表空间,用于存放不同表、索引和其他数据库对象的数据文件。
- 表空间可以帮助管理存储和备份策略,以及控制数据库对象的存放位置。
-
页(Pages):
- 页是 PostgreSQL 存储数据的最小单位。
- 页的默认大小是 8KB,它是数据库中数据读取和写入的基本单元。
- 数据文件被分成多个固定大小的页,每个页可以存储一条或多条记录。
-
行(Rows):
- 行是数据库表中的记录。
- 行存储了表的列(字段)的实际数据和元数据。
- 行是数据库中数据的基本单位,每个页可以包含多行数据。
-
目录(Catalogs):
- 目录是 PostgreSQL 中的系统表,用于存储数据库的元数据信息。
- 目录包含了数据库对象的定义和属性信息,例如表、列、索引、触发器等。
- 目录中的数据用于支持数据库的查询优化、数据字典和元数据查询。
-
索引(Indexes):
- 索引是用于加快数据访问和查询速度的数据结构。
- 索引存储了数据的键和指向对应数据位置的指针。
- PostgreSQL 支持多种类型的索引,如 B-tree、哈希索引、GIN 索引等。
-
日志(Logs):
- 日志是用于记录数据库操作的文件。
- PostgreSQL 的日志分为事务日志(Transaction Log)和归档日志(Archive Log)。
- 事务日志记录了对数据库的修改操作,用于实现事务的持久性和恢复能力。
- 归档日志用于备份和恢复数据库。
这些组件一起构成了 PostgreSQL 数据库的存储结构。它们协同工作,管理和存储数据,支持高效的数据访问和查询操作,并提供数据库的持久性和一致性。
脏页
在 PostgreSQL 中,“脏页”(Dirty Pages)是指在内存中的数据页(Page)与对应的磁盘上的数据不一致的情况。当对数据库进行写操作时,PostgreSQL首先将修改的数据写入内存中的对应数据页,而不是直接写入磁盘。这样可以提高性能,因为内存的读写速度比磁盘快得多。
当数据页被修改但还未写入磁盘时,该页被标记为"脏页"。这意味着内存中的数据与磁盘上的数据不一致。为了保证数据的一致性和持久性,PostgreSQL使用一种称为"写前日志"(Write Ahead Logging,WAL)的机制。该机制在进行数据写入操作之前,将修改操作记录到WAL文件中。这样,在系统崩溃或重新启动后,可以使用WAL文件来恢复脏页的数据。
当数据库系统需要回收内存或者将数据写入磁盘时,它会检查脏页的状态。如果脏页已经被持久化到磁盘上,那么系统可以安全地丢弃该页并释放内存。如果脏页尚未持久化,系统会将脏页写入磁盘,然后再进行释放操作。
脏页的存在是为了在性能和数据一致性之间进行平衡。通过将修改的数据暂时保存在内存中,可以避免频繁地写入磁盘,提高性能。然而,这也增加了系统发生故障时数据丢失的风险。因此,PostgreSQL使用WAL机制来保证脏页的数据持久性和一致性。
区别
PostgreSQL和Oracle是两种不同的关系型数据库管理系统,它们在处理脏页(Dirty Pages)方面有一些区别。
-
写前日志(Write Ahead Logging)机制:
- PostgreSQL:在PostgreSQL中,使用WAL机制来记录对数据的修改操作。在进行数据写入之前,将修改操作记录到WAL文件中,以保证数据的持久性和一致性。
- Oracle:Oracle也使用日志(Redo Log)来记录对数据的修改操作,但它采用了不同的机制。Oracle的日志是基于块(Block)的,即记录对数据库块的修改,而不是对单个数据页的修改。这种机制被称为“块日志记录”(Block-Level Logging)。
-
脏页写入机制:
- PostgreSQL:PostgreSQL使用后台进程(Background Writer)定期将脏页写入磁盘。后台写入过程是异步的,即修改操作首先写入内存中的数据页,然后由后台进程负责将脏页写入磁盘。
- Oracle:Oracle也有类似的后台进程(DBWn,Database Writer),负责将脏页写入磁盘。但是,Oracle使用的写入策略是基于时序的(Time-Based),即定期将脏页写入磁盘,而不是在特定条件下立即写入。
-
检查点(Checkpoint)机制:
- PostgreSQL:PostgreSQL使用检查点来管理脏页的写入。检查点是一种特殊的操作,它将所有的脏页写入磁盘,以确保数据库的一致性和持久性。
- Oracle:Oracle也有类似的检查点机制,被称为“日志刷新”(Log Flush)。当发生检查点操作时,Oracle会将所有的脏页写入磁盘,并将相应的日志记录标记为已刷新。
总体而言,PostgreSQL和Oracle在处理脏页方面有一些相似之处,例如使用后台进程进行脏页写入和使用检查点机制来保证数据的一致性。然而,它们在写前日志机制和脏页写入策略上存在一些差异,这些差异是由它们各自的架构和设计哲学所决定的。
redo & undo
在 PostgreSQL 和 Oracle 数据库中,“redo”(重做日志)和 “undo”(撤销日志)是用于实现事务的关键日志机制,它们在两个数据库系统中有以下区别:
-
Redo 日志:
- PostgreSQL:PostgreSQL使用"写前日志"(Write Ahead Log,WAL)来记录 redo 日志。WAL 包含了对数据库中数据的修改操作,在事务提交之前先将修改操作记录到 WAL 文件中。这样可以确保在系统故障时,可以使用 WAL 日志来重做未持久化的修改,恢复数据库到一致状态。
- Oracle:Oracle使用 redo 日志来记录对数据库块的修改操作。redo 日志包含了对数据块的物理修改,以及事务的提交和回滚信息。它用于确保数据库在故障恢复时的一致性和持久性。
-
Undo 日志:
- PostgreSQL:PostgreSQL没有明确的 “undo” 日志概念。相反,PostgreSQL使用多版本并发控制(MVCC)来管理并发事务的读写一致性。每个事务在修改数据时,会创建一个新的版本,并在需要时保留旧版本的数据。这样可以实现事务的隔离性和回滚操作,而无需显式的 “undo” 日志。
- Oracle:Oracle使用 “undo” 日志记录事务的修改操作,以便实现回滚和读一致性。“undo” 日志记录了对数据库块的逻辑修改,在回滚时可以使用 “undo” 日志将数据库恢复到之前的状态。此外,“undo” 日志还用于支持多版本并发控制(MVCC),允许读取旧版本的数据,从而实现可重复读的隔离级别。
-
目的和用途:
- Redo 日志:用于确保数据库的持久性和一致性,并在系统故障后恢复未持久化的修改。
- Undo 日志:用于回滚事务和提供读一致性,确保读取的数据在事务开始时的一致性状态。
总结起来,PostgreSQL 和 Oracle 在 redo 和 undo 日志的概念和实现上有一些区别。PostgreSQL使用 WAL 来记录 redo 日志,而没有明确的 undo 日志概念,而 Oracle 使用 redo 和 undo 日志来记录物理修改和逻辑修改,以实现持久性、一致性、回滚和读一致性等功能。
PostgreSQL使用多版本并发控制(MVCC)
在 PostgreSQL 中,多版本并发控制(MVCC)是一种并发控制机制,它通过为每个事务创建不同的数据版本来实现事务的隔离性和回滚操作,而无需显式的 “undo” 日志。
下面是具体解释 PostgreSQL 中 MVCC 的工作原理:
-
版本化数据:在 PostgreSQL 中,每个数据行都可以存在多个版本。当一个事务修改数据行时,它会创建一个新的数据版本,并将该版本与事务关联。这个新版本包含了事务进行修改之前的数据副本。
-
事务的读操作:当一个事务需要读取数据时,它会获得一个特定时间点的快照,称为 “读取视图” 或 “事务视图”。这个视图定义了在该时间点可见的数据版本。事务只能看到在其开始之前已经提交的数据版本,而不会看到其他事务未提交的修改。
-
事务的写操作:当一个事务需要修改数据时,它会创建一个新的数据版本,并将该版本与事务关联。这个新版本会包含事务进行修改之前的数据副本。原始的数据版本不会直接被修改,而是保留在磁盘上。其他并发事务仍然可以读取原始的数据版本。
-
事务的隔离性:通过使用 MVCC,每个事务都在自己的数据版本上进行读写操作,而不会干扰其他事务。这样,不同事务之间可以并发地读写相同的数据,彼此之间不会产生冲突。每个事务都能够看到一致性的数据视图,从而实现了事务的隔离性。
-
回滚操作:当一个事务需要回滚时,它只需丢弃或忽略自己所创建的数据版本即可。其他事务可以继续读取原始的数据版本,而不受回滚操作的影响。因为每个事务修改的数据版本与其他事务相互独立,所以回滚只需要废弃当前事务的修改,而无需撤销其他事务的修改。
通过使用 MVCC,PostgreSQL 实现了并发事务的读写一致性。每个事务在修改数据时会创建一个新的数据版本,并在需要时保留旧版本的数据。这样,不同事务可以并发地读写相同的数据,而不会相互干扰。同时,每个事务都能够看到一致性的数据视图,实现了事务的隔离性和回滚操作的效率,而无需显式地记录和撤销事务的修改。
Oracle 隔离级别
Oracle数据库支持多个隔离级别,以控制并发事务之间的相互影响程度。下面是Oracle数据库中支持的隔离级别:
-
READ COMMITTED(读已提交):
- 这是Oracle数据库的默认隔离级别。
- 在该隔离级别下,事务只能读取到已提交的数据。事务读取的数据不会受到其他事务未提交修改的影响。
- 该级别可以防止脏读(Dirty Read),但仍可能发生不可重复读(Non-repeatable Read)和幻读(Phantom Read)。
-
SERIALIZABLE(串行化):
- 在该隔离级别下,事务会按照顺序逐个执行,每个事务之间是串行执行的。
- 这是最高的隔离级别,可以避免脏读、不可重复读和幻读的问题。
- 由于事务串行执行,因此并发性能较差,可能会影响系统的吞吐量。
此外,Oracle数据库还支持一些其他的隔离级别,它们提供了特定的并发控制机制。这些隔离级别主要用于特定的应用场景和需求,如并发性能优化和数据一致性要求。以下是其中一些隔离级别:
-
READ ONLY(只读):
- 在该隔离级别下,事务只能进行读操作,不能进行写操作。
- 这种隔离级别适用于只读事务,可以提供最高的并发性能,因为读操作不需要加锁。
-
READ WRITE(读写):
- 这是Oracle数据库默认的读写隔离级别。
- 事务可以进行读操作和写操作,但可能会遇到脏读、不可重复读和幻读的问题。
-
SERIALIZABLE WITH ROW SHARE(带行共享的串行化):
- 这是一种增强的串行化隔离级别,它在串行化级别的基础上引入了行级共享锁。
- 这种隔离级别可以提供更高的并发性能,同时避免了脏读、不可重复读和幻读的问题。
需要注意的是,不同的隔离级别具有不同的特性和性能影响。在选择隔离级别时,需要综合考虑应用的并发需求、数据一致性要求和性能需求,并进行适当的权衡。