1.oracle 资料库内存结构简介
当实例启动时,Oracle数据库分配内存区域并启动后台进程。
内存区域存储如下信息:
- 程式码
- 每个会话已连接信息,包含未活动的会话
- 程序执行期间所需的信息,例如,从中获取行的查询的当前状态
- 进程间共享和通信的锁数据等信息
- 存在于磁盘上的缓存数据,例如数据块和重做记录
1.1 基本内存结构
Oracle 数据库包含多个内存区域,每个内存区域包含多个子组件。
与 Oracle 数据库相关的基本内存结构包括:
System global area (SGA)
SGA 是一组共享内存结构(称为 SGA 组件),其中包含一个 Oracle 数据库实例的数据和控制信息。所有服务器和后台进程共享SGA。存储在 SGA 中的数据示例包括缓存数据块和共享 SQL 区域。
Program global area (PGA)
PGA 是一个非共享内存区域,包含专门供 Oracle 进程使用的数据和控制信息。 Oracle 数据库在 Oracle 进程启动时创建 PGA。 每个服务器进程和后台进程都存在一个 PGA。各个 PGA 的集合是总实例 PGA,或实例 PGA。数据库初始化参数设置实例 PGA 的大小,而不是单个 PGA。
User global area (UGA)
UGA 是与用户会话相关的内存。
Software code areas
软件代码区域是用于存储正在运行或可以运行的代码的内存部分。 Oracle 数据库代码存储在软件区域中,该区域通常与用户程序位于不同的位置 - 更排他或更受保护的位置
下图说明了这些内存结构之间的关系
1.2 oracle 数据库 内存管理
内存管理涉及根据数据库需求的变化维护 Oracle 实例内存结构的最佳大小。 Oracle数据库根据内存相关初始化参数的设置来管理内存。
内存管理的基本选项如下:
##自动内存管理(Automatic memory management) AMM
您指定数据库实例内存的目标大小。实例自动调整到目标内存大小,根据需要在 SGA 和实例 PGA 之间重新分配内存。
##自动共享内存管理(Automatic shared memory management)ASMM
这种管理模式是部分自动化的。您可以为 SGA 设置目标大小,然后可以选择为 PGA 设置聚合目标大小或单独管理 PGA 工作区。
##手动内存管理(Manual memory management)
您无需设置总内存大小,而是设置许多初始化参数来单独管理 SGA 和实例 PGA 的组件。
如果使用数据库配置助手 (DBCA) 创建数据库并选择基本安装选项,则自动内存管理是默认设置。
2.用户全局区概述(UGA) Overview of the User Global Area
UGA 是会话内存,它是为会话变量分配的内存,例如登录信息和数据库会话所需的其他信息。本质上,UGA 存储会话状态。
如果会话将 PL/SQL 包加载到内存中,则 UGA 包含包状态,它是在特定时间存储在所有包变量中的一组值。当包子程序更改变量时,包状态也会发生变化。默认情况下,包变量对于会话来说是唯一的并且在会话的生命周期中持续存在。
OLAP页池也存储在UGA中。该池管理OLAP数据页,相当于数据块。页池在 OLAP 会话开始时分配,并在会话结束时释放。每当用户查询维度对象(例如多维数据集)时,OLAP 会话就会自动打开。
UGA 必须在数据库会话的生命周期内可用。因此,当使用共享服务器连接时,UGA 不能存储在 PGA 中,因为 PGA 是特定于单个进程的。因此,当使用共享服务器连接时,UGA 存储在 SGA 中,使得任何共享服务器进程都可以访问它。当使用专用服务器连接时,UGA 存储在 PGA 中。
3.程序全局区域(PGA)概述 Overview of the Program Global Area (PGA)
PGA 是特定于操作进程或线程的内存,不与系统上的其他进程或线程共享。由于 PGA 是特定于进程的,因此永远不会在 SGA 中分配它。
PGA 是一个内存堆,其中包含专用或共享服务器进程所需的会话相关变量。服务器进程在 PGA 中分配所需的内存结构。
PGA 可以类比为文件管理员使用的临时台面工作空间。在这个类比中,文件管理员是代表客户(客户端进程)执行工作的服务器进程。店员清理了台面的一部分,使用工作区存储有关客户请求的详细信息并对客户请求的文件夹进行排序,然后在工作完成后放弃空间。
下图显示了未配置共享服务器的实例的实例 PGA(所有 PGA 的集合)。您可以使用初始化参数来设置实例 PGA 的目标最大大小。各个 PGA 可以根据需要增长到该目标大小。
PGA 的内容
PGA 被细分为不同的区域,每个区域都有不同的目的,下图显示了专用服务器会话的 PGA 的可能内容并非所有 PGA 区域都存在。
当服务器进程执行SQL或PL/SQL代码时,该进程使用私有SQL区域来存储绑定变量值、查询执行状态信息和查询执行工作区域。 注意:不要将PGA中的私有SQL区域与SGA中存储执行计划的共享SQL区域混淆,相同或不同会话中的多个私有SQL区域可以指向SGA中的单个执行计划。
例如,在一个会话中执行 20 次 SELECT * FROM sales 以及在不同会话中执行 10 次相同查询可以共享相同的计划。每次执行的私有SQL区域不共享,并且可能包含不同的值和数据。
游标是特定私有 SQL 区域的名称或句柄。如下图所示,您可以将光标视为客户端的指针和服务器端的状态。由于游标与私有 SQL 区域密切相关,因此这些术语有时可以互换使用。
A private SQL area is divided into the following areas:私有SQL区分为以下几个区域
运行时区域 The run-time area:
该区域包含查询执行状态信息。例如,运行时区域跟踪迄今为止在全表扫描中检索到的行数。
Oracle 数据库创建运行时区域作为执行请求的第一步。对于DML语句,当SQL语句关闭时,运行时区域被释放。
持久区 The persistent area :
该区域包含绑定变量值。绑定变量值在运行时执行 SQL 语句时提供给该语句。仅当游标关闭时,持久区域才会被释放。
客户端进程负责管理私有SQL区域。尽管客户端进程可以分配的私有 SQL 区域的数量受到初始化参数 OPEN_CURSORS 的限制,但私有 SQL 区域的分配和释放很大程度上取决于应用程序。
尽管大多数用户依赖于数据库实用程序的自动游标处理,但 Oracle 数据库编程接口为开发人员提供了对游标的更多控制。一般来说,应用程序应该关闭所有不会再次使用的打开游标,以释放持久区域并最大限度地减少应用程序用户所需的内存。
在前面的示例中,运行时区域跟踪全表扫描的进度。会话在哈希区域中执行哈希联接以匹配两个表中的行。 ORDER BY 排序发生在排序区域中。
如果操作员要处理的数据量无法容纳在一个工作区中,则 Oracle 数据库会将输入数据划分为更小的块。这样,数据库会在内存中处理一些数据,而将其余数据写入临时磁盘存储以供稍后处理。
当启用自动 PGA 内存管理时,数据库会自动调整工作区大小。您还可以手动控制和调整工作区域的大小。有关详细信息,请参阅“内存管理”。
通常,较大的工作区域可以显着提高操作员的性能,但代价是更高的内存消耗。最佳情况下,工作区的大小足以容纳输入数据和由其关联的 SQL 运算符分配的辅助内存结构。否则,响应时间会增加,因为部分输入数据必须缓存在磁盘上。在极端情况下,如果工作区的大小与输入数据大小相比太小,则数据库必须对数据块执行多次传递,从而显着增加响应时间。
专用和共享服务器模式下的 PGA 使用
PGA 内存分配取决于数据库是使用专用服务器连接还是共享服务器连接
4.系统全局区(SGA)概述 Overview of the System Global Area (SGA)
SGA是一个读/写内存区域,它与Oracle后台进程一起构成数据库实例。
注意:服务器进程和后台进程并不驻留在SGA内,而是存在于单独的内存空间中。
所有代表用户执行的服务器进程都可以读取实例 SGA 中的信息。在数据库操作期间,有多个进程写入 SGA。
每个数据库实例都有自己的SGA。 Oracle 数据库在实例启动时自动为 SGA 分配内存,并在实例关闭时回收内存。当您使用 SQL*Plus 或 Oracle Enterprise Manager 启动实例时,SGA 的大小如下例所示:
SGA 由多个内存组件组成,这些组件是用于满足特定类别的内存分配请求的内存池。除重做日志缓冲区之外的所有 SGA 组件都以称为颗粒的连续内存为单位分配和释放空间。颗粒大小是特定于平台的,并且由总 SGA 大小决定。
您可以查询 V$SGASTAT 视图以获取有关 SGA 组件的信息。
最重要的 SGA 组件如下:
数据库缓冲区高速缓存(Database Buffer Cache)
数据库缓冲区高速缓存也称为缓冲区高速缓存,是存储从数据文件读取的数据块副本的内存区域。
缓冲区是缓冲区管理器临时缓存当前或最近使用的数据块的主存储器地址。同时连接到数据库实例的所有用户共享对缓冲区高速缓存的访问。
数据库缓冲区高速缓存的用途:
Oracle 数据库使用缓冲区高速缓存来实现多个目标。
目标包括:
优化物理 I/O:
数据库更新缓存中的数据块,并将有关更改的元数据存储在重做日志缓冲区中。 COMMIT 后,数据库将重做缓冲区写入联机重做日志,但不会立即将数据块写入数据文件。相反,数据库编写器 (DBW) 在后台执行延迟写入。
将经常访问的块保留在缓冲区高速缓存中,并将不经常访问的块写入磁盘:
当Database Smart Flash Cache(闪存缓存)启用时,部分缓冲区缓存可以驻留在闪存缓存中。该缓冲区高速缓存扩展存储在一个或多个闪存盘设备上,这些闪存盘设备是使用闪存的固态存储设备。数据库可以通过在闪存中缓存缓冲区而不是从磁盘读取来提高性能。
使用 DB_FLASH_CACHE_FILE 和 DB_FLASH_CACHE_SIZE 初始化参数来配置多个闪存设备。缓冲区高速缓存跟踪每个设备并将缓冲区统一分配给设备。
注意:数据库智能闪存缓存仅在 Solaris 和 Oracle Linux 中可用。
缓冲状态
数据库使用内部算法来管理缓存中的缓冲区。
缓冲区可以处于以下任意互斥状态:
--未使用
该缓冲区可供使用,因为它从未使用过或当前未使用。这种类型的缓冲区是数据库最容易使用的。
--干净的
该缓冲区以前使用过,现在包含截至某个时间点的块的读取一致版本。该块包含数据,但是是“干净的”,因此不需要检查点。数据库可以固定该块并重用它。
--肮脏的
缓冲区包含尚未写入磁盘的已修改数据。数据库必须在重用该块之前对其进行检查点。
每个缓冲区都有一种访问模式:固定或自由(未固定)。缓冲区被“固定”在高速缓存中,以便在用户会话访问它时不会出现内存不足的情况。多个会话无法同时修改固定缓冲区。
缓冲模式
当客户端请求数据时,Oracle 数据库以当前模式或一致模式从数据库缓冲区高速缓存中检索缓冲区。
这些模式的区别如下:
--当前模式
当前模式获取(也称为数据库块获取)是对当前出现在缓冲区高速缓存中的块的检索。例如,如果未提交的事务已更新块中的两行,则当前模式 get 会检索包含这些未提交行的块。数据库在修改语句期间最频繁地使用db block gets,该语句必须仅更新块的当前版本。
--一致模式
一致读取获取是对块的读取一致版本的检索。该检索可以使用撤消数据。例如,如果未提交的事务已更新块中的两行,并且如果单独会话中的查询请求该块,则数据库使用撤消数据创建该块的读一致版本(称为一致性读克隆)这不包括未提交的更新。通常,查询以一致模式检索块。
缓冲输入/输出
逻辑I/O,也称为缓冲区I/O,是指对缓冲区高速缓存中缓冲区的读取和写入。
当内存中找不到请求的缓冲区时,数据库会执行物理 I/O,将缓冲区从闪存缓存或磁盘复制到内存中。然后数据库执行逻辑 I/O 来读取缓存的缓冲区。
缓冲区替换算法
为了使缓冲区访问高效,数据库必须决定哪些缓冲区要缓存在内存中,哪些缓冲区要从磁盘访问。
该数据库使用以下算法:
基于 LRU 的块级替换算法
这种复杂的默认算法使用最近最少使用 (LRU) 列表,其中包含指向脏缓冲区和非脏缓冲区的指针。 LRU链表有热端和冷端。冷缓冲区是最近未使用过的缓冲区。热缓冲区被频繁访问并且最近被使用过。从概念上讲,只有一个 LRU,但为了数据并发,数据库实际上使用了多个 LRU。
基于温度的对象级替换算法
从 Oracle Database 12c 第 1 版 (12.1.0.2) 开始,自动大表缓存功能允许表扫描在以下场景中使用不同的算法:
--并行查询
在单实例和 Oracle Real Applications Cluster (Oracle RAC) 数据库中,当 DB_BIG_TABLE_CACHE_PERCENT_TARGET 初始化参数设置为非零值并且 PARALLEL_DEGREE_POLICY 设置为 auto 或 adjustment 时,并行查询可以使用大表缓存。
--串行查询
仅在单实例配置中,当 DB_BIG_TABLE_CACHE_PERCENT_TARGET 初始化参数设置为非零值时,串行查询可以使用大表缓存。
当表无法容纳在内存中时,数据库会根据访问模式决定缓存哪些缓冲区。例如,如果流行表中只有 95% 适合内存,那么数据库可能会选择将 5% 的块保留在磁盘上,而不是循环地将块读入内存并将块写入磁盘,这种现象称为抖动。当缓存多个大对象时,数据库认为更受欢迎的表更热,而不太受欢迎的表更冷,这会影响缓存哪些块。 DB_BIG_TABLE_CACHE_PERCENT_TARGET 初始化参数设置使用此算法的缓冲区高速缓存的百分比。
注意:本文档解释了基于 LRU 的块级替换算法。
缓冲区写入
数据库写入器 (DBW) 进程定期将冷的脏缓冲区写入磁盘。
DBW 在以下情况下写入缓冲区:
##服务器进程无法找到干净的缓冲区来将新块读入数据库缓冲区高速缓存。
##当缓冲区变脏时,空闲缓冲区的数量就会减少。如果该数字低于内部阈值,并且需要清理缓冲区,则服务器进程会向 DBW 发出写入信号。
##数据库使用 LRU 来确定要写入哪些脏缓冲区。当脏缓冲区到达 LRU 的冷端时,数据库将它们从 LRU 移至写入队列。 DBW 将队列中的缓冲区写入磁盘,如果可能,使用多块写入。这种机制可以防止 LRU 的末端被脏缓冲区堵塞,并允许找到干净的缓冲区以供重用。
##数据库必须提前检查点,这是重做线程中实例恢复必须开始的位置。
##表空间更改为只读状态或脱机。
缓冲区读取
当未使用的缓冲区数量较低时,数据库必须从缓冲区高速缓存中删除缓冲区。
该算法取决于是否启用闪存缓存:
闪存缓存已禁用:
数据库根据需要重新使用每个干净的缓冲区,并覆盖它。如果以后需要覆盖的缓冲区,那么数据库必须从磁盘读取它。
启用闪存缓存:
DBW 可以将干净缓冲区的主体写入闪存缓存,从而实现其内存缓冲区的重用。数据库将缓冲区标头保存在主内存中的 LRU 列表中,以跟踪缓冲区主体在闪存高速缓存中的状态和位置。如果稍后需要此缓冲区,则数据库可以从闪存缓存而不是从磁盘读取它。
当客户端进程请求缓冲区时,服务器进程会在缓冲区高速缓存中搜索该缓冲区。如果数据库在内存中找到缓冲区,则会发生缓存命中。搜索顺序如下:
1)服务器进程在缓冲区高速缓存中搜索整个缓冲区。
如果进程找到整个缓冲区,则数据库执行该缓冲区的逻辑读取。
2)服务器进程在闪存缓存LRU 列表中搜索缓冲区标头。
如果进程找到缓冲区标头,则数据库会执行缓冲区主体从闪存缓存到内存缓存的优化物理读取。
3)如果进程在内存中找不到缓冲区(高速缓存未命中),则服务器进程将执行以下步骤:
a.将块从磁盘上的数据文件复制到内存(物理读取)
b.对读入内存的缓冲区执行逻辑读取
扩展缓冲区高速缓存包括内存缓冲区高速缓存(包含整个缓冲区)和闪存高速缓存(包含缓冲区主体)。图中,数据库在缓冲区高速缓存中搜索缓冲区,如果找不到缓冲区,则从磁盘将其读入内存。
缓冲区搜索”说明
一般来说,通过缓存命中访问数据比通过缓存未命中访问数据更快。缓冲区高速缓存命中率衡量数据库在缓冲区高速缓存中找到请求的块而无需从磁盘读取该块的频率。
数据库可以从数据文件或临时文件执行物理读取。从数据文件读取之后是逻辑 I/O。当内存不足迫使数据库将数据写入临时表并稍后读回时,就会从临时文件中读取数据。这些物理读取绕过缓冲区高速缓存并且不会产生逻辑 I/O。
缓冲区触摸计数
数据库使用触摸计数来测量 LRU 列表上缓冲区的访问频率。此机制使数据库能够在固定缓冲区时增加计数器,而不是不断地对 LRU 列表上的缓冲区进行改组。
注意:数据库不会物理移动内存中的块。移动是指针在列表上位置的变化。
当缓冲区被固定时,数据库确定其触摸计数最后一次增加的时间。如果计数在三秒前增加,则计数增加;否则,计数保持不变。三秒规则可防止缓冲区上的引脚突发计数相同的触摸次数。例如,一个会话可能会在一个数据块中插入几行,但数据库将这些插入视为一次操作。
如果缓冲区位于 LRU 的冷端,但其触摸计数较高,则缓冲区会移至热端。如果触摸计数较低,则缓冲区会从高速缓存中老化。
缓冲池
缓冲池是缓冲区的集合。
数据库缓冲区高速缓存分为一个或多个缓冲池,它们以基本相同的方式管理块。这些池没有完全不同的老化或缓存块算法。
您可以手动配置单独的缓冲池,将数据保留在缓冲区高速缓存中,或者在使用数据块后立即使缓冲区可用于新数据。然后,您可以将特定的架构对象分配给适当的缓冲池,以控制块如何从缓存中老化。例如,您可以将段分为热缓冲池、温缓冲池和冷缓冲池。
可能的缓冲池如下:
默认池Default pool
该池是通常缓存块的位置。除非您手动配置单独的池,否则默认池是唯一的缓冲池。其他池的可选配置对默认池没有影响。
从 Oracle Database 12c 第 1 版 (12.1.0.2) 开始,大表缓存是默认池的可选部分,它使用基于温度的对象级替换算法。在单实例和 Oracle RAC 数据库中,当 DB_BIG_TABLE_CACHE_PERCENT_TARGET 初始化参数设置为非零值并且 PARALLEL_DEGREE_POLICY 设置为 auto 或 adjustment 时,并行查询可以使用大表缓存。仅在单实例配置中,当设置 DB_BIG_TABLE_CACHE_PERCENT_TARGET 时,串行查询可以使用大表缓存。
保留泳池 Keep pool
该池适用于经常访问但由于空间不足而在默认池中老化的块。 keep缓冲池的目的是将对象保留在内存中,从而避免I/O操作。
注意:keep池以与其他池相同的方式管理缓冲区:它不使用特殊的算法来固定缓冲区。 “保持”一词是一种命名约定。您可以将想要保留的表放置在较大的保留池中,并将不想保留的表放置在较小的回收池中。
回收池 Recycle pool
该池适用于不经常使用的块。回收池可防止对象消耗缓存中不必要的空间。
数据库具有标准的块大小。您可以创建块大小与标准大小不同的表空间。每个非默认块大小都有自己的池。 Oracle 数据库以与默认池中相同的方式管理这些池中的块。
下图展示了使用多个pool时的buffer cache的结构。缓存包含默认池、保留池和回收池。默认块大小为 8 KB。缓存包含使用 2 KB、4 KB 和 16 KB 非标准块大小的表空间的单独池。
缓冲区和全表扫描
数据库使用复杂的算法来管理表扫描。默认情况下,当必须从磁盘读取缓冲区时,数据库会将缓冲区插入到 LRU 列表的中间。这样,热块就可以保留在缓存中,这样就不需要再次从磁盘读取它们。
全表扫描会带来一个问题,它会顺序读取表高水位线 (HWM) 下的所有行。假设表段中块的总大小大于缓冲区高速缓存的大小。对此表的完整扫描可能会清除缓冲区高速缓存,从而阻止数据库维护频繁访问的块的高速缓存。
全表扫描的默认模式
默认情况下,数据库对全表扫描采取保守的方法,仅当表大小占缓冲区缓存的一小部分时才将小表加载到内存中。
为了确定是否应该缓存中型表,数据库使用了一种算法,该算法结合了上次表扫描之间的时间间隔、缓冲区高速缓存的老化时间戳以及缓冲区高速缓存中的剩余空间。
对于非常大的表,数据库通常使用直接路径读取,将块直接加载到 PGA 中并完全绕过 SGA,以避免填充缓冲区缓存。对于中等大小的表,数据库可以使用直接读取或缓存读取。如果决定使用缓存读取,则数据库会将块放置在 LRU 列表的末尾,以防止扫描有效地清除缓冲区缓存。
从 Oracle Database 12c 第 1 版 (12.1.0.2) 开始,数据库实例的缓冲区缓存会自动执行内部计算,以确定内存是否足以将数据库完全缓存在实例 SGA 中,以及访问时缓存表是否会有利于性能。如果整个数据库可以完全装入内存,并且满足各种其他内部标准,则 Oracle 数据库会将数据库中的所有表视为小表,并认为它们有资格进行缓存。但是,数据库不会缓存标有 NOCACHE 属性的 LOB。
并行查询执行
执行全表扫描时,数据库有时可以通过使用多个并行执行服务器来提高响应时间。
在某些情况下,当数据库具有大量内存时,数据库可以将并行查询数据缓存在系统全局区域(SGA)中,而不是使用直接路径读取到程序全局区域(PGA)中。通常,由于潜在的资源使用,并行查询发生在低并发数据仓库中。
缓存属性 CACHE Attribute
在不需要默认缓存行为的极少数情况下,您可以使用 ALTER TABLE ... CACHE 更改将大表中的块读入数据库缓冲区缓存的方式。
对于设置了 CACHE 属性的表,数据库不会强制或固定缓冲区高速缓存中的块。相反,数据库会以与任何其他表块相同的方式将块从缓存中老化。执行此选项时要小心,因为对大表的完整扫描可能会清除缓存中的大多数其他块。
注意:执行 ALTER TABLE ... CACHE 不会导致表被缓存。
保留属性 KEEP Attribute
对于大型表,您可以使用 ALTER TABLE ... STORAGE BUFFER_POOL KEEP 来进行扫描,将这些表的块加载到保留池中。
将表放入保留池会更改缓冲区高速缓存中存储块的部分。数据库不会将块缓存在默认缓冲池中,而是将它们缓存在保留缓冲池中。没有单独的算法控制来保持池缓存。
强制完整数据库缓存模式 Force Full Database Caching Mode
为了提高某些情况下的性能,您可以显式执行 ALTER DATABASE ... FORCE FULL DATABASE CACHING 语句来启用强制全数据库缓存模式。
与自动的默认模式相反,强制完整数据库缓存模式将整个数据库(包括 NOCACHE LOB)视为有资格在数据库缓冲区高速缓存中进行缓存。此模式从 Oracle Database 12c 第 1 版 (12.1.0.2) 开始可用。
注意:启用强制完整数据库缓存模式不会强制数据库进入内存。相反,整个数据库都可以缓存在缓冲区高速缓存中。 Oracle 数据库仅在访问表时才缓存表。
Oracle 建议仅当每个实例的缓冲区缓存大小大于数据库大小时才启用强制完整数据库缓存模式。本指南适用于单实例数据库和 Oracle RAC 数据库。但是,当 Oracle RAC 应用程序分区良好时,当所有实例的组合缓冲区高速缓存(具有处理实例之间重复高速缓存块的额外空间)大于数据库大小时,您可以启用强制完整数据库高速缓存模式。
内存区域 (In-Memory Area)
内存区域是一个可选的 SGA 组件,其中包含内存列存储(IM 列存储)。
IM 列存储包含针对快速扫描而优化的列式格式的表、分区和物化视图的副本。 IM 列存储补充了以传统行格式存储数据的数据库缓冲区高速缓存。
注意:要启用 IM 列存储,您必须具有 Oracle Database In-Memory 选项。
内存优化池Memoptimize Pool
memoptimize 池存储指定为 MEMOPTIMIZE FOR READ 的堆组织表的缓冲区和相关结构。
此结构为基于键的查询(例如 SELECT * FROM cust WHERE cid = 10)提供了高性能和可扩展性。为了减少端到端响应时间,客户端通过网络直接从 SGA 提取请求的缓冲区,从而避免了 CPU 和操作系统开销。应用程序可以从 memoptimize 池中受益,而无需更改代码。
memoptimize 池包含两部分 The memoptimize pool contains two parts:
Mem优化缓冲区
为了避免磁盘 I/O,数据库会永久锁定 memoptimize 池中 MEMOPTIMIZE FOR READ 表的缓冲区,直到该表被标记为 NO MEMOPTIMIZE FOR READ。 memoptimize 缓冲区使用与数据库缓冲区高速缓存中的缓冲区相同的结构。但是,memoptimize 池中的缓冲区与数据库缓冲区高速缓存完全分开,并且不计入其大小。 memoptimize 缓冲区占 memoptimize 池的 75%。
哈希索引
哈希索引是一种非持久的段数据结构。数据库将哈希索引分配为多个不连续的内存单元。每个单元包含多个哈希桶。单独的映射结构将内存单元与主键相关联。哈希索引占用 memoptimize 池的 25%。
要启用 memoptimize 池,请将 MEMOPTIMIZE_POOL_SIZE 初始化参数设置为整数值(默认情况下禁用该池)。该值指定分配给池的 SGA 量。 MEMOPTIMIZE_POOL_SIZE 值确实计入 SGA_TARGET,但数据库不会自动增长和收缩 memoptimize 池。例如,如果 SGA_TARGET 为 10 GB,并且 MEMOPTIMIZE_POOL_SIZE 为 1 GB,则除 memoptimize 池之外,总共有 9 GB 可用于 SGA 内存。
要更改 memoptimize 池的大小,您必须手动设置 MEMOPTIMIZE_POOL_SIZE 并重新启动数据库实例。您无法使用 ALTER SYSTEM 动态更改池大小。
DBMS_MEMOPTIMIZE 包使您能够将表显式填充到 memoptimize 池中。
重做日志缓冲区(Redo Log Buffer)
重做日志缓冲区是 SGA 中的循环缓冲区,用于存储描述对数据库所做的更改的重做条目。
重做记录是一种数据结构,其中包含重建或重做通过 DML 或 DDL 操作对数据库所做的更改所需的信息。数据库恢复将重做条目应用于数据文件以重建丢失的更改。
数据库进程将重做条目从用户内存空间复制到SGA中的重做日志缓冲区。重做条目占用缓冲区中连续的、顺序的空间。后台进程日志写入进程 (LGWR) 将重做日志缓冲区写入磁盘上的活动联机重做日志组。图 显示了此重做缓冲区活动。
LGWR 将重做顺序写入磁盘,而 DBW 将数据块分散写入磁盘。分散写入往往比顺序写入慢得多。由于 LGWR 使用户能够避免等待 DBW 完成其缓慢的写入,因此数据库提供了更好的性能。
LOG_BUFFER 初始化参数指定 Oracle 数据库在缓冲重做条目时使用的内存量。与其他 SGA 组件不同,重做日志缓冲区和固定 SGA 缓冲区不会将内存划分为颗粒。
共享池(Shared Pool)
共享池缓存各种类型的程序数据。
例如,共享池存储解析后的SQL、PL/SQL代码、系统参数和数据字典信息。数据库中发生的几乎所有操作都会涉及到共享池。例如,如果用户执行一条SQL语句,那么Oracle数据库就会访问共享池。
- Library Cache
库缓存是一个共享池内存结构,用于存储可执行的 SQL 和 PL/SQL 代码。
该缓存包含共享 SQL 和 PL/SQL 区域以及控制结构(例如锁和库缓存句柄)。在共享服务器体系结构中,库高速缓存还包含私有 SQL 区域。
当执行 SQL 语句时,数据库会尝试重用先前执行的代码。如果 SQL 语句的解析表示存在于库缓存中并且可以共享,则数据库会重用该代码,称为软解析或库缓存命中。否则,数据库必须构建应用程序代码的新可执行版本,称为硬解析或库缓存未命中。
共享 SQL 区 Shared SQL Areas
数据库代表它在共享SQL区和私有SQL区中运行的每条SQL语句。
数据库使用共享 SQL 区来处理第一次出现的 SQL 语句。该区域可供所有用户访问,包含语句解析树和执行计划。对于一条唯一的语句,仅存在一个共享 SQL 区域。每个发出 SQL 语句的会话在其 PGA 中都有一个私有 SQL 区域。每个提交相同语句的用户都有一个私有SQL区域,指向同一个共享SQL区域。因此,不同 PGA 中的许多私有 SQL 区域可以与同一个共享 SQL 区域关联。
数据库自动确定应用程序何时提交类似的 SQL 语句。数据库既考虑用户和应用程序直接发出的 SQL 语句,也考虑其他语句内部发出的递归 SQL 语句。
数据库执行以下步骤:
1)检查共享池以查看是否存在语法和语义相同的语句的共享 SQL 区域:
如果存在相同的语句,则数据库将使用共享 SQL 区来执行该语句的后续新实例,从而减少内存消耗。
如果不存在相同的语句,则数据库在共享池中分配一个新的共享 SQL 区域。语法相同但语义不同的语句使用子游标。
无论哪种情况,用户的私有 SQL 区域都指向包含语句和执行计划的共享 SQL 区域。
2)代表会话分配私有 SQL 区域
私有 SQL 区域的位置取决于为会话建立的连接。如果会话通过共享服务器连接,则部分私有 SQL 区域将保留在 SGA 中。
显示了一个专用服务器体系结构,其中两个会话在各自的 PGA 中保留相同 SQL 语句的副本。在共享服务器中,该副本位于UGA中,UGA位于大型池中,或者当不存在大型池时位于共享池中。
程序单元和库高速缓存 Program Units and the Library Cache
库缓存保存可执行形式的 PL/SQL 程序和 Java 类。这些项目统称为程序单元。
数据库处理程序单元的方式与SQL语句类似。例如,数据库分配一个共享区域来保存已解析、已编译形式的 PL/SQL 程序。数据库分配一个私有区域来保存特定于运行程序的会话的值,包括本地变量、全局变量和包变量,以及用于执行 SQL 的缓冲区。如果多个用户运行同一个程序,则每个用户都会维护其私有 SQL 区域的单独副本,该副本保存特定于会话的值,并访问单个共享 SQL 区域。
如前所述,数据库处理 PL/SQL 程序单元内的各个 SQL 语句。尽管它们起源于 PL/SQL 程序单元,但这些 SQL 语句使用共享区域来保存其解析的表示形式,并为运行该语句的每个会话使用私有区域。
共享池中内存的分配和重用 Allocation and Reuse of Memory in the Shared Pool
当解析新的SQL语句时,数据库会分配共享池内存,除非该语句是DDL,否则不被认为是可共享的。分配的内存大小取决于语句的复杂性。
一般来说,共享池中的项目会一直保留,直到数据库根据最近最少使用 (LRU) 算法将其删除。只要多个会话使用的共享池项有用,数据库就允许它们保留在内存中,即使创建该项的数据库进程终止也是如此。这种机制最大限度地减少了 SQL 语句的开销和处理。如果新项目需要空间,则数据库会释放不常用项目消耗的内存。
ALTER SYSTEM FLUSH SHARED_POOL 语句会删除共享池中的所有信息,就像更改全局数据库名称一样。
- Data Dictionary Cache
数据字典是数据库表和视图的集合,其中包含有关数据库、数据库结构和用户的参考信息。
Oracle数据库在解析SQL语句时会频繁访问数据字典。 Oracle 数据库经常访问数据字典,因此指定以下特殊内存位置来保存字典数据:
--数据字典缓存
该缓存保存有关数据库对象的信息。缓存也称为行缓存,因为它以行而不是缓冲区的形式保存数据。
--库缓存
所有服务器进程共享这些缓存以访问数据字典信息。
- Server Result Cache
服务器结果缓存是共享池内的内存池。与缓冲池不同,服务器结果缓存保存结果集而不是数据块。
服务器结果缓存包含SQL查询结果缓存和PL/SQL函数结果缓存,它们共享相同的基础结构。
注意:客户端结果缓存与服务器结果缓存不同。客户端缓存是在应用程序级别配置的,位于客户端内存中,而不是数据库内存中。
SQL查询结果缓存 SQL Query Result Cache
SQL 查询结果缓存是服务器结果缓存的子集,用于存储查询结果和查询片段。
大多数应用程序都受益于这种性能改进。考虑一个重复运行相同 SELECT 语句的应用程序。如果结果被缓存,那么数据库会立即返回它们。这样,数据库就避免了重新读取块和重新计算结果的昂贵操作。
当查询执行时,数据库会搜索内存以确定结果是否存在于结果缓存中。如果结果存在,则数据库从内存中检索结果而不是执行查询。如果结果未缓存,则数据库执行查询,返回结果作为输出,然后将结果存储在结果缓存中。每当事务修改用于构造缓存结果的数据库对象的数据或元数据时,数据库就会自动使缓存结果失效。
用户可以使用 RESULT_CACHE 提示来注释查询或查询片段,以指示数据库应将结果存储在 SQL 查询结果缓存中。 RESULT_CACHE_MODE 初始化参数确定 SQL 查询结果缓存是用于所有查询(如果可能)还是仅用于带注释的查询。
PL/SQL Function Result Cache
PL/SQL 函数结果缓存是存储函数结果集的服务器结果缓存的子集。
如果没有缓存,以每次调用 1 秒的速度调用 1000 次函数将需要 1000 秒。通过缓存,具有相同输入的 1000 个函数调用总共可能需要 1 秒。结果缓存的良好候选者是依赖于相对静态数据的频繁调用的函数。
PL/SQL 函数代码可以包含缓存其结果的请求。调用此函数后,系统会检查缓存。如果缓存中包含前一个具有相同参数值的函数调用的结果,则系统将缓存的结果返回给调用者,并且不会重新执行函数体。如果缓存不包含结果,则系统将执行函数体并将结果(对于这些参数值)添加到缓存,然后将控制权返回给调用者。
注意:您可以指定Oracle数据库用于计算缓存结果的数据库对象,这样,如果其中任何一个被更新,缓存结果将变得无效并且必须重新计算。
缓存可以累积许多结果,即调用每个结果缓存函数所用的参数值的每个唯一组合的一个结果。如果数据库需要更多内存,那么它就会使一个或多个缓存结果过期。
- 预留池 Reserved Pool
保留池是共享池中的一个内存区域,Oracle 数据库可使用它来分配大的连续内存块。
数据库从共享池中以块的形式分配内存。分块允许将大对象(超过 5 KB)加载到缓存中,而不需要单个连续区域。这样,数据库就减少了因为碎片而耗尽连续内存的可能性。
有时,Java、PL/SQL 或 SQL 游标可能会从共享池中进行大于 5 KB 的分配。为了使这些分配最有效地进行,数据库将少量共享池隔离为保留池。
大型泳池(Large Pool)
大池是一个可选的内存区域,用于大于适合共享池的内存分配。
大池可以为以下各项提供大内存分配:
用于共享服务器和 Oracle XA 接口的 UGA(在事务与多个数据库交互的情况下使用)
并行执行中使用的消息缓冲区
恢复管理器 (RMAN) I/O 从站的缓冲区
延迟插入的缓冲区(带有 MEMOPTIMIZE_WRITE 提示的插入)
大池内存管理
大池管理内存的方式与共享池不同,共享池使用 LRU 列表,以便部分内存可以老化。
Large Pool 没有 LRU 列表。当数据库将大池内存分配给数据库会话时,除非会话释放它,否则该内存不符合释放条件。一旦释放了一部分内存,其他进程就可以使用它。通过从大池中分配会话内存,数据库可以避免共享池中可能出现的碎片。
Java池(Java Pool)
Java 池是存储 Java 虚拟机 (JVM) 内所有特定于会话的 Java 代码和数据的内存区域。该内存包括在调用结束时迁移到 Java 会话空间的 Java 对象。
对于专用服务器连接,Java 池包括每个 Java 类的共享部分,包括方法和只读存储器(例如代码向量),但不包括每个会话的每个会话 Java 状态。对于共享服务器,池包括每个类的共享部分和一些用于每个会话状态的UGA。每个 UGA 都会根据需要增大和缩小,但 UGA 的总大小必须适合 Java 池空间。
Java Pool Advisor 统计信息提供有关用于 Java 的库高速缓存内存的信息,并预测 Java 池大小的变化如何影响解析率。当statistics_level设置为TYPICAL或更高时,Java Pool Advisor在内部打开。当顾问关闭时,这些统计数据会重置。
固定SGA(Fixed SGA)
固定SGA是一个内部管理区域。
例如,固定SGA包含:
有关后台进程需要访问的数据库和实例状态的一般信息
进程之间传递的信息,例如有关锁的信息
固定SGA的大小由Oracle数据库设置,不能手动更改。固定的 SGA 大小可能会随着版本的不同而变化。
可选的与性能相关的 SGA 子区域(Optional Performance-Related SGA Subareas)
某些 SGA 子区域仅针对特定性能功能启用。
内存区域
内存优化池
5.软件代码区域概述
软件代码区域是存储正在运行或可以运行的代码的存储器的一部分。 Oracle 数据库代码存储在软件区域中,该区域通常比用户程序的位置更具排他性和受保护性。
软件区域的大小通常是静态的,仅在软件更新或重新安装时才会改变。这些区域所需的大小因操作系统而异。
软件区护性只读的,可以共享或非共享安装。某些数据库工具和实用程序(例如 Oracle Forms 和 SQL*Plus)可以共享安装,但有些则不能。如果可能,数据库代码是共享的,以便所有用户都可以访问它,而无需在内存中拥有多个副本,从而减少主内存并整体提高性能。如果在同一台计算机上运行,数据库的多个实例可以将相同的数据库代码区域与不同的数据库一起使用。
注意:安装共享软件的选项并非适用于所有操作系统,例如,在运行 Microsoft Windows 的 PC 上。有关详细信息,请参阅特定于操作系统的文档。