前言
通过本文你可以对Oracle的底层数据结构包括物理层面和逻辑层面有一个大致的了解,无论你学没学过Oracle数据库。更详细的内容可以自己查阅官方文档,部分结构是直接截取的官方图示,更直观明了,没有做重复的复刻。如果文中有理解错误的地方,请各位路过的大佬纠正。Oracle官方网站:Oracle。本文针对的数据库版本为Oracle 19c,部分概念会进行扩展详解,部分会进行简单描述。如果觉得篇幅比较长,可以只看某几个你感兴趣的概念或者结构,如果要彻彻底底的说清楚,可能这篇文章的长度是远远不够的。希望这篇文章对大家有帮助。后续会持续更新干货,写出对大家有帮助的文章。
Oracle底层数据存储结构
在逻辑层面,Oracle数据库使用了**数据块(block)、连续数据块(extents,数据范围)、数据段(segment)**进行表示。
在物理层面,Oracle数据库将数据存储在磁盘上的数据文件中(data files)。
在了解Oracle底层数据存储之前,先了解操作系统中是怎么做存储。
1. 操作系统基本存储了解
在Linux中使用多种文件操作系统,其中最常用的是ext4(第四文件扩展系统,在centos5用的是ext3,在centos6用的是ext4,在centos7用的是xfs)。当然还包括btrfs。
在Windows中使用的是NTFS(New Technology File System)作为其主要的文件系统。Windows98以前使用的是FAT文件系统,在Windows2000版本后才开始使用NTFS文件系统。
macos早期使用的是HFS+文件系统,现在使用的是APFS(Apple File System)作为其文件系统。
1.1 操作系统中的簇(块)、扇区
数据持久化到硬盘中涉及到磁盘的扇区与操作系统的块(簇)。在windows中称为簇,在Linux和macOs中称为块,后面统称为块。
**块是操作系统中读写的基本单位,磁盘读取的基本单位是扇区。**操作系统是以块作为最基本单位来对数据进行操作。
扇区是磁盘最小的物理存储单元,是磁头从磁盘中读取数据的最小单位(一般为512B)。磁头每次从磁盘中读取数据都是一个扇区一个扇区的进行读取。但是操作系统无法对数据众多的扇区进行寻址,所以操作系统将相邻的扇区组合形成一个块,然后在对块进行管理。
块是操作系统与硬盘交互的最基本单位(最小数据单元)。操作系统从磁盘中拿出一块数据,即完成了一次磁盘IO。
块的大小一般在磁盘进行格式化是就已经确定好了,一般有1k,2k,3k,4k,其中4k是最常用的一种大小。如果块的大小设置为4k,那么磁头需要读取八个扇区(512B)后,才将数据块传给操作系统。
一个文件在存储时,无论它的大小是否满足整数块,多出的部分会独占一个块大小,假设一个文件大小为1k,而块的默认大小为4k,那么就会有3k的空间空闲出来,且不能用于存储其他数据。同理,假设大小为5k,那么就会占用两个块。
扇区是对硬盘而言的,是物理层面的。而块是对文件系统而言的,是逻辑层次的。磁盘控制器是用来映射两层的,即操作系统到硬盘。
1.2 块、扇区的定义
该图与部分内容参考来自:博客
在物理层面上面,一个磁盘按层次划分为磁盘组合->某个磁盘->某一个盘面->某一磁道->某一扇区。
扇区是指,在磁盘的盘面上划分了多个磁道,每部分的弧长加上到圆心的半径就构成了一个扇形,这部分称为扇区。扇区是磁盘中最小的物理存储单位。通常情况下每个扇区的大小是512字节,但随着技术的进步和时代的发展,一些新的存储设备可是采用更大的扇区,部分产品的扇区大小是4k。对于机械硬盘仍使用着扇区的概念,但是随着固态硬盘(SSD)技术的发展与普及,不再严格遵循传统磁盘的物理扇区概念,而是将数据存储在更大的逻辑单元中(SSD也是用逻辑扇区的概念,最基本存储单位为page)。
在逻辑层面上面,是块,块是操作系统中最小的存储单位,操作系统通过块与磁盘进行交互。块是由多个扇区组成,扇区的数量为2的n次方个。操作系统规定一个块只能放置一个文件的内容,因此文件所占用的空间只能是块的整数倍,如果文件大小实际小于一个块的大小,那么它也要占一块,所以一般情况下文件所占空间要略微大于文件的实际大小。
块的大小主要是由磁盘的分区的格式和容量大小来决定的。
1.3 为什么用块
- 读取方便,由于扇区数目众多,导致寻址会比较困难,所以操作系统就将相邻的扇区组合在一起形成一个块,在对块进行整体操作。
- 分离对底层的依赖:操作系统忽略对底层物理存储结构的设计。通过虚拟出来磁盘块的概念,在系统中认为块是最小的单位。
1.4 总结
-
通过磁盘控制器(读取数据,控制磁头),来映射扇区和块的关系。
-
文件系统操作文件的最小单位是块。
-
一个块的大小为一个扇区的大小*2的n次方。
blockSize = sectorSize * 2 ^ n
-
如果块的大小刚好是扇区的整数倍,那么对于磁盘的IO读取更快,更好,如果不是整数倍会导致扇区割裂。
-
块是一个逻辑概念,它的大小是由操作系统决定。
-
操作系统与内存进行打交道时使用的时以页作为最小单位。
2. Oracle物理存储
2.1 物理存储结构
2.1.1 数据文件与临时文件
数据文件是由Oracle数据库所创建,文件中包含一些数据结构如表结构、索引结构等等,它们会被持久化存储。临时文件归属于临时表空间,它存储着一些临时数据,这些数据只在会话持续期间存在。
2.1.2 主控文件
主控文件是一个二进制文件,它记录着数据库的物理结构,包括名称、redo log文件的地址,数据库的创建时间,当前日志序列号,检查点(check point)信息等。
检查点是一个标记检查位置的数据结构,分为局部检查点,文件检查点,全局检查点。它们被记录在控制文件和每个数据文件的头部,是数据恢复的关键元素。
2.1.3 online redo files
online redo files 是一组数据更改记录文件,它们记录着对Oracle数据库的数据文件和主控文件所做的所有更改。当对数据库进行更改时,Oracle数据库会在redo buffer生成记录,后面由日志记录写入进程(LGWR)将redo buffer缓冲中的更改记录写入online redo file中。
2.2 数据库实例
数据库实例是一组管理数据库文件的内存结构,它存储在SGA中。
2.2.1 SGA
SGA(System Global Area),它是一个内存共享区,用ddddddddddddddddddd所需要的数据,缓存和控制信息等。
SGA包括:
- 缓冲区高速缓存:用来存储最近从数据文件中读写过的数据。
- 共享池(shared pool):用来存储最近执行的SQL语句和最近使用的数据字典的数据。
- redo log buffer:用来记录服务、事务或后台进程对数据库所作的更改。
- java池:用来存储java对象和类的地方。
- 大池(large pool):用于存储一些较大的内存结构。
- 流池(steam pool):用于支持Oracle streams(Oracle消息相关)相关功能。
2.3 数据文件(data files)
从操作系统层面看,Oracle数据库将数据存储在称为数据文件(data files)中。一组数据文件被分在tablespace的逻辑空间中。Oracle数据库通过分配指定数量的磁盘空间为表空间创建数据文件(data files),并在给文件加上文件头。文件头包含一些文件元数据,包括大小、check point scn,唯一标识号。
Extent(连续块)可以是已使用的,意味着它们包含段数据,或者是空闲的,意味着它们可用于重新使用。随着时间的推移,表空间内对象的更新和删除可能会创建一些空白空间,这些空间单独来看可能很小,但无法重新用于新数据。这种类型的空白空间被称为碎片化的空闲空间。
2.4 控制文件(control files)
数据库控制文件是一个仅与一个数据库相关联的小型二进制文件。每个数据库都有自己唯一的控制文件。
Oracle使用主控文件来定位数据库文件并管理数据库的状态。
主控文件包含:
- 数据库名称以及数据库唯一标识。
- 数据库的创建时间。
- 表空间信息。
- 数据文件、online redo log、压缩的redo log files的相关信息(位置)。
当数据库的物理结构发生改变时,Oracle会自动更新控制文件。
2.5 online redo log files
online redo log files是数据库所维护的一个用于记录数据更改的日志文件,可以防止数据丢失。具体来说,在实例故障后,online redo log files使Oracle数据库能够恢复尚未写入数据文件的已提交数据。在线重做日志的内容包括未提交的事务、数据库对象和对象管理语句(DML)。
online redo log 由两个或者多个online redo files 组成。对于Oracle实例来说online redo log 被称为redo thread,每个Oracle实例都有自己单独的redo thread。online redo files 之所以至少为两个,是因为Oracle数据库要保证一个文件在被更改时,另外一个文件可以被写入。
Oracle数据库每次只会使用一个online redo log file从redo log buffer中写入记录。
2.6 存储结构图示
3. Oracle逻辑存储
Oracle的逻辑存储结构包括数据块(data block)、段(segment)、连续数据块(extent)、表空间(tablespace)。
一个段是由一组extent组成,分配给特定的数据库对象。每一个存储的数据库对象都有自己的段。
表空间是Oracle数据库存储的基本单位,它包含一个或者多个段,每个段仅属于一个表空间。在一个表空间内,一个段(Segment)可以包括来自多个数据文件的区(Extent)
在表空间中,通过使用位图(bitmap)的形式来管理连数据块,因此本地表空间会留出一部分空间存储位图。
3.1 数据块
Oracle数据库在**data files管理逻辑空间的最小单位是数据块(data blocks)。**一个逻辑数据块对应磁盘一定数量的物理空间,数据块是oracle数据库使用或者分配的最小单位(存储表数据、索引、数据库对象等数据)。
Oracle 数据块是数据库内部用于管理数据和存储的概念,而操作系统数据块是操作系统用于管理磁盘上数据的概念。两者在本质上存在着不同,主要区别是数据库块是Oracle数据库内部的逻辑数据存储单位,而操作系统块是操作系统与硬盘交互的最小单位。Oracle数据库是在操作系统上运行的,并使用操作系统块来读取和写入数据库数据文件,数据库块的大小通常是大于操作系统的块大小,数据库块大小一般为8k。数据库文件包含一个个逻辑数据库块,Oracle数据库引擎负责它们与操作系统块的映射关系,而操作系统的块是由一组2^n个扇区组成,扇区和块的映射关系是磁盘控制器负责的。
DB_BLOCK_SIZE参数可以在数据库创建时指定数据块的大小,该大小一旦确定就不可以更改,除非重新创建数据库。如果不指定该参数的话,数据库的默认块大小为8kb或者4kb,如果块大小与操作系统的块大小不同,那么数据库块大小必须时操作系统块大小的整数倍。
Oracle数据库使用block overhead来管理数据块本身,block overhead中不存储任何用户数据,它包含一下部分:
-
块头部(block header)
它包含一些常规的数据信息,如磁盘地址,块类型等,它还包含当前和历史事务信息。
-
表目录(table directory)
目录中包含存储在该块中的表元数据信息。在集群环境下,多个表的数据可以存储在同一个块中。
-
行目录(row directory)
这个目录描述了数据块中数据行所在的位置,Oracle数据库可以将行数据放在数据块底部的任何位置。
rowId指向一个具体文件、块或者行号。行号在行目录中表示索引。行目录中的实体包含指向数据块上行的地址。
3.1.1 行数据的存储(row data)
Oracle数据库使用row header来管理存储在数据块中的row pieces(一行行实际数据,不一定是完整的一行数据,称为行片)。行片是由行头和列数据组成。
为什么Oracle数据库会把一行数据拆分为行片呢?
因为当整个数据能够直接插入数据块中时,那么整行数据会被存储为一个行片,但是如果行数据无法全部插入到一个单独的块中,或者更新操作导致改行的大小超出数据库块的现有大小,Oracle数据库会把一行数据拆分成多个行片进行存储。通常情况下每行数据只有一个行片(未进行拆分)。row header的大小至少要有3B的大小。
列数据(column data)所存储的是真正的数据,行片存储列数据的顺序是与create table创建数据库时保持一致的。Oracle数据库会将列的长度和列数据进行分开存储,所需要的空间去决定列的数据类型,如果列的数据类型是可变长度的,那么数据存储空间会随着值的改变而改变。
Oracle数据库使用rowid来唯一标识一行数据,rowid上包含着数据库访问行数据所需要的信息,rowid不会进行物理存储而是从存储数据的文件和块中推断出来的。rowid是一个虚拟列。
格式:
当一行数据很大,一个数据库块不足以容纳时,Oracle数据库会使用行链来解决这个问题,将行的数据存储多个数据块中,并使用行链进行连接。
当行数据发生更新,导致行整体的长度增加,没有足够的空间来容乃新的行数据,此时就会发生行迁移,Oracle数据库会将该行整体迁移到新的数据块中,假设这个数据库可以容纳该行,原始行片会包含一个指向新行片的地址。
Oracle数据库的行片最多存储255列的数据。
3.2 区(连续数据块,Extents)
区在逻辑上是由相邻的或者一组连续的数据块组成,是data file中的逻辑数据结构之一,用于存储特定的信息。默认情况下当段(segment)创建时会生成一个默认的区。
扩展机制是怎样的呢?
当初始化的区存储满数据后,需要更多的空间来进行数据存储,数据库会为这个区分配一个增量区,增量区是为段创建的新区。
一个段的区可能在不同的data file中,但是一定在同一个表空间中,需要扩充时,数据库会搜索数据文件的位图找到相邻的空闲块,如果相邻的数据块空间不足,数据库就会在另外一个数据文件中进行寻找,这会导致一个段的区可能在不同的数据文件中。
新分配的区,可能不是空的,但一定是空闲可使用的,当进行使用时,会对增量区进行格式化处理。
除非使用drop语句删除一个数据库对象,否则用户段中的区空间不会返还给表空间。例如,当删除一个表中的所有行时,删除前所占的数据块并不会被立即回收,而是供表空间的其他数据库对象使用。
3.3 段(segment)
段由一个或者多个区构成,是表空间中的逻辑数据结构之一。Oracle数据库的table是通过段来进行保存的。
Oracle数据库为数据库表分配一个或者多个区构成数据段,同时也会分配一个或者多个区构成索引段给数据库表的索引。
默认情况下,当创建表、索引、分区时,数据库会延迟创建段,该方式只会更新数据库的元数据信息。
CLOB是large object的意思,ClLOB有着自己的段。
3.3.1 临时段
当执行查询语句时,Oracle数据库通常会用到一个临时的空间,去存储语句执行时产生的一些数据,比如大量的排序,连接,临时存储结果集时作为一个临时的工作空间,以便执行这些操作而不会占用data file的空间。
举个列子说,当Oracle数据库创建索引时,会有对应的索引段,它不是一开始就将创建好的索引段进行持久化,而是将这个索引段放到临时段中,等索引创建完成后再将临时段中的索引段进行持久化。由此可以看出,临时段是作为一个临时的工作空间。
**需要注意的是,当操作可以在内存中完成时,Oracle数据库并不会去创建临时段。**反之如果内存不可用,数据库就会在磁盘上分配一个临时段。
在用户session持续期间,Oracle数据库会根据需要分配一个临时段给查询使用并且在查询完成后删除它们。临时段的操作不会被记录到online redo log中,除非是对临时段进行空间调整。
临时段的回收和分配非常频繁,最好是给临时段创建一个特殊的表空间,就是临时表空间,通过临时表空间进行临时段的分配。
3.3.2 撤销段
Oracle维护事务操作记录,统称为撤销数据(undo data)。它主要的作用是维护事务的一致性、并发和回滚操作。
撤销段(undo segment)有如下作用:
-
回滚事务。
撤销段中存储了未提交事务所作的更改,以便在需要时执行回滚操作。
-
可并发。
撤销段允许多个事务同时访问相同的数据,每个事务都可以看到自己的版本数据,而不受其他事务干扰。
-
提供数据读一致性。
撤销段中存储了已提交事务的历史版本数据,以便其他事务在需要时进行查看和使用。当一个事务进行时,其他事务可以通过撤销段访问该事务已经提交的数据。这意味着一个事务正在进行读取操作时不会看到其他正在进行中的事务未提交的数据。
undo segment存储在撤销表空间中。
undo segment和事务:
当事务开始时,数据库将事务分配到当前撤销表空间中的撤销段中,从而分配到事务表中,在极少数情况下,如果数据库实例没有指定undo表空间,那么事务就会被分配到系统撤销段中。
补充:Oracle数据库如何实现并发事务读一致性的?
当一个事务开启时它会创建一个当前时间节点的数据库快照,它只能看到在该数据快照之前已经提交的数据,而不会看到该快照之后未提交的事务所作的更改,这个是通过Oracle数据库的隔离级别实现的(Read Committed)。
数据隔离级别机制不在本文讨论,本文只讨论数据库的存储原理和结构。
3.4 表空间
表空间是段的逻辑存储容器,段是数据库的一些对象,如表、索引等,消耗存储空间。在物理层面,表空间对应着一个或者多个数据文件或者临时数据文件。
数据库默认创建的表空间有system、sysaux、undo、temp表空间。
表空间分为永久性表空间、临时性表空间两大类。具体来说永久表空间有SYSTEM表空间、SYSAUX表空间、Shadow表空间。
3.4.1 永久性表空间
SYSTEM表空间
SYSTEM表空间是创建数据库时包含的必要表空间。它包括数据字典、管理数据库的表和视图信息、存储编译过的一些对象如触发器等。
默认情况下Oracle数据库将将所有新创建的用户表空间设置为本地管理。
-
数据字典
数据字典包含了数据库中各种对象的元数据信息,如表视图的一些描述信息(表名、列名,数据类型) 、系统参数和初始化参数、数据库版本信息等。
SYSAUX表空间
SYSAUX表空间是SYSTEM表空间的辅助表空间。
undo表空间
该表空间是存储系统管理的undo数据。跟其它表空间一样,它也有数据文件。一个数据库可以有一个或者多个undo表空间,但是同一时间,只有一个数据库实例可以访问。有一个撤销保留其概念,是指Oracle数据库保留旧的undo数据的最小时间。
3.4.2 临时表空间
临时表空间仅包含在会话期间持续存在的临时数据,用于数据库内部的排序、连接、临时表等操作,查询产生的数据通常存储在临时段中。
共享和本地临时表空间
临时表空间既可以是共享的也是非共享的(本地)。
共享的临时表空间将数据存放在磁盘上一块共享的区域,以便其他数据库实例能够访问,相反本地临时表空间存储的临时文件对于每个数据库实例是非共享的。
默认表空间
每个数据库用户都被分配了一个默认的临时表空间。如果数据库包含本地临时表空间,则还会为每个用户帐户分配默认的本地临时存储。
3.4.3 表空间模式
表空间分为可读写表空间、只读表空间、在线表空间(可访问, online)、非在线表空间(不可访问,offline)。系统表空间和临时表空间不能为Offline模式。
3.4.4 表空间的作用
表空间的作用有:
-
决定数据库实体的空间分配
-
设置数据库用户的空间份额
-
控制数据库部分数据的可用性
-
分布数据于不同的设备之间以改善性能
-
备份和恢复数据。
每个数据库实例是非共享的。
默认表空间
每个数据库用户都被分配了一个默认的临时表空间。如果数据库包含本地临时表空间,则还会为每个用户帐户分配默认的本地临时存储。
3.4.3 表空间模式
表空间分为可读写表空间、只读表空间、在线表空间(可访问, online)、非在线表空间(不可访问,offline)。系统表空间和临时表空间不能为Offline模式。
3.4.4 表空间的作用
表空间的作用有:
-
决定数据库实体的空间分配
-
设置数据库用户的空间份额
-
控制数据库部分数据的可用性
-
分布数据于不同的设备之间以改善性能
-
备份和恢复数据。