Oracle数据库由 `实例` 和 `数据库` 两部分构成。Oracle数据库启动后,会在操作系统内存中划分出来一块独立的区域,并且在后台启动一些进程,而划分出来的内存和后台进程统称为 `实例`。
`实例` 为访问数据库提供了入口,通常来说,一个数据库对应一个数据库的实例。而在某些特殊的结构中,一个数据库会对应多个数据库实例。例如,一个 `RAC` 数据库会对应至少两个数据库的实例。
而数据库在启动过程中向操作系统内存申请的内存则称为 `SGA(System Global Area,系统全局区)`。`系统全局区SGA` 是一组共享内存结构,其中包含Oracle数据库的数据文件信息和控制文件信息。SGA提供给所有Oracle数据库的实例和后台进程共享,因此,系统全局区也被称为 `共享全局区(Shared Gloabl Area)`。
在数据库启动后,内存中的一块独立区域(可能是提前划分好的)被用来存放Oracle数据库的一些基本信息,而这块划分出来的区域 `SGA` 通常包含以下6个部分,`Shared Pool(共享池)`、`Stream Pool(流池)`、`Large Pool(大型池)`、`Java Pool(java池)`、`Database Buffer Cache(数据库缓冲区高速缓存)` 和 `Redo Log Buffer(重做日志缓冲区)`。
如下图,为Oracle SGA内存结构图
-
Database Buffer Cache
: Oracle实例SGA内存区域至关重要的一块内存区域。主要用于提升数据库的访问性能。通常,当用户进程连接到数据库实例时,在数据库中会产生大量的I/O请求,而当用户进程需要查询或修改的数据库不在内存(`Database Buffer Cache`)高速缓冲区中时,不可避免需要将数据库存储在硬盘上的数据加载到高速缓存区中,而每当数据库需要从硬盘中提取数据到缓冲区时,则需要进行操作系统层面的I/O操作。 而倘若用户进程连接到数据库中的查询请求的数据已经存在在 `Database Buffer Cache` 中时,数据库会直接从缓冲区中读入数据并将数据返回给用户请求。当请求数据被从数据库缓冲区中返回时,则称为一次缓存命中(hit)。显然,数据库中缓存命中可以极大提升数据库的访问性能。 也因此,数据库的 `Database Buffer Cache` 内存区域的空间应该尽可能大一些,从而减少数据库进入硬盘读取数据而产生的I/O事件。 但受限于操作系统内存的容量限制,`SGA` 不可能无限制的大。因此,`SGA` 内存结构中的各个结构区域也有各自的大小。而当 `Database Buffer Cache` 高速缓存区被塞满时,则需要清除掉部分不经常被访问的数据,以便将缓存中经常需要访问的数据保留下来实现更高的缓存命中率,提升数据库的访问性能。 当下一次用户进程请求 `Database Buffer Cache` 中并不存在的数据时,数据库则会重新进入硬盘中找到并提取数据到高速缓冲区中。数据库高速缓冲区中主要包含三种类型的数据块,根据数据块的类型分为 `脏数据区(Dirty Buffers)`、`自由区(Free Buffers)`、 `保留区(Pinned Buffers)`。
脏数据区: 指数据库中的数据被修改后尚未写入到硬盘中。在数据库中,仅写入到磁盘中的数据才会被称为干净数据。因为数据库缓存区的数据极有可能因为各种原因无法写入到硬盘中,造成数据丢失从而导致数据库出现数据不一致的问题。
自由区: 指数据库中的干净区域,没有被使用过的区域。自由区中,数据库可以随时向该区域写入数据,通常从硬盘中读入的数据会放入干净区中。
保留区: 涉及到修改或正在操作的区域,或有其他用途的区域。
-
Shared Pool
: 共享池缓存。主要用来存储可以被不同用户共享的重复SQL语句、数据字典中的信息。共享池是SGA中用来缓存程序数据的区域。主要包含 **可重用的SQL语句**、**数据字典信息**、**SQL存储过程**等。共享池主要包含两个部分,一部分是 `Library Cache`,另一部分是 `Data Dictionary Cache`。
Libray Cache 主要用来缓存用户执行过的SQL语句及PL/SQL的相关信息,缓存的主要信息包含用户执行过的SQL语句文本、执行结果及执行计划。位于该缓存区的SQL语句或执行计划同时会共享给其他不同的用户,当其他用户在数据库中执行同样的SQL语句或执行计划时,位于 Libray Cache
缓存区的执行结果将返回给其他用户而无需重新在数据库中执行一次相同的SQL语句。
显然当数据库中有大批用户需要查询相同的数据时,使用系统的sql语句会极大提高数据库的响应速度,而这正是因为数据库的相同的SQL语句文本及执行结果、执行计划被缓存到 `Linrary Cache` 中了。
Data Dictionary Cache: 该部分缓存区主要缓存数据字典相关的一些信息,例如,用户账户数据、数据表及索引、及权限等信息。使用数据字典缓存,可以缩短数据的解析响应时间。
-
Redo Log Buffer
: 重做日志缓冲区,主要用来记录数据库发生的事务变更。通常用户进程连接到数据库后,不可避免需要对数据中的数据进行增删改善,而涉及到被修改的数据,Oracle数据库会将被修改的数据相关信息写入到 `Redo Log Buffer` 中,最后通过 `LGWR` 后台进程将缓存区的日志写入到 Redo Log 日志文件中。 需要注意的是,Oracle数据库对于已修改数据并不是数据发生修改后直接写回到硬盘的,而是将修改数据后产生的相关信息写入到日志中,而 `Redo Log Buffer` 缓存区的日志按照一定的规则将数据库变更的记录刷新到日志文件中。`Redo Log Buffer` 缓存区的容量并不会很大,而缓存区的日志写入到日志文件中也是按照数据发生修改的时间点按**顺序写入**,因此写入日志的性能要高于将数据写回到磁盘中。 Redo Log 所记录的日志文件对于Oracle数据库的故障恢复有着非常重大的帮助。通过将修改后的数据写入到redo log日志文件中,即便处于缓存区的数据没有写入到硬盘上时数据库发生了故障,也能在数据库下一次启动时通过应用 redo log 日志中的记录将数据库再一次恢复到数据库崩溃前的状态,保障数据的一致性。
-
Large Pool
: 大池,主要用于缓存数据库中的大型I/O请求。在一些场景下,数据库会出现大量并行查询的进程,而并行查询会产生从属进程,这些从属进程需要消耗额外的内存空间,而这些空间正式由
Large Pool
提供的。另外,在一些共享模式(Shared Server
)的场景下,用户连接所需要的共享内存也会由Large Pool
分配。在备份恢复的时候,启用异步I/O需要设置Large Pool
以支持异步I/O模式。
-
Java Pool
: java池,数据库中运行java代码时需要使用该内存区域。
-
Stream Pool
: 流池。数据库中的数据可以通过流
的方式共享。使用Oracle流,共享信息的每个单元称为一条消息,可以在流中共享一条条消息。流不仅可以在数据库中共享信息,而且支持在数据库间共享信息,使用流可以将一个数据库的信息传播到另一个数据库。
参考: SGA、 oracle SGA详解