Oracle DB 内存结构
Oracle DB 针对各种用途创建和使用内存结构。例如,使用内存来存储正在运行的程序代
码、在各用户之间共享的数据以及所连接的每个用户的专用数据区域。
一个实例有两个关联的基本内存结构:
• 系统全局区(SGA):称为SGA 组件的共享内存结构组,这些组件包含一个Oracle DB 实例的数据和控制信息。
SGA 由所有服务器和后台进程共享。SGA 中存储的数据示例包括高速缓存的数据块和共享SQL 区域。
• 程序全局区(PGA):包含某个服务器进程或后台进程的数据及控制信息的内存区域。
PGA 是Oracle DB 在服务器进程或后台进程启动时创建的非共享内存。
服务器进程对PGA 的访问是互斥的。
每个服务器进程和后台进程都具有自己的PGA。
1、SGA&PGA
SGA 是包含实例的数据和控制信息的内存区。SGA 包含以下数据结构:
• 数据库缓冲区高速缓存:用于缓存从数据库中检索到的数据块
• 重做日志缓冲区:用来缓存用于实例恢复的重做信息,直到可以将其写入磁盘中存储的物理重做日志文件
• 共享池:用于缓存可在用户间共享的各种结构
• 大型池:为某些大型进程(例如Oracle 备份和恢复操作)和I/O 服务器进程提供大型内存分配的可选区域。
• Java 池:用于Java 虚拟机(JVM) 中特定于会话的所有Java 代码和数据
• 流池:Oracle Streams 使用它来存储捕获和应用操作所需的信息
使用Oracle Enterprise Manager 或SQL*Plus 启动实例时,将会显示为SGA 分配的内存量。
程序全局区(PGA) 是一个内存区,其中包含每个服务器进程的数据及控制信息。Oracle服务器进程为客户机请求提供服务。
每个服务器进程都有自己专用的PGA,其PGA 在服务器进程启动时创建,对PGA 的访问权限仅限于该服务器进程,并且只能由代表该服务器进程的Oracle代码对PGA进行读写。
使用动态SGA 基础结构,可以在不关闭实例的情况下更改数据库缓冲区高速缓存、共享池、大型池、Java 池和流池的大小。
Oracle DB 使用初始化参数来创建和管理内存结构。管理内存的最简单的方法是允许数据库自动管理和优化内存。
要做到这一点(以下操作适用于大多数平台),只需设置目标内存大小初始化参数(MEMORY_TARGET) 和最大内存大小初始化参数
(MEMORY_MAX_TARGET)。
2、数据库缓冲区高速缓存
数据库缓冲区高速缓存是SGA 的一部分,用于存放从数据文件读取的数据块的副本。并行连接到实例的所有用户共享对数据库缓冲区高速缓存的访问。
Oracle DB 用户进程第一次需要特定数据片段时,将在数据库缓冲区高速缓存中搜索数据。
如果该进程在高速缓存中找到数据(称为高速缓存命中),则直接从内存中读取数据。
如果进程在高速缓存中找不到数据(称为高速缓存未命中),则在访问数据之前,必须将磁盘上的数据文件中的数据块复制到高速缓存中的缓冲区中。
高速缓存命中时访问数据要比高速缓存未命中时访问数据快。
高速缓存中的缓冲区由一个复杂算法管理,该算法组合使用最近最少使用(LRU) 列表和停靠计数机制。
服务器进程和数据库缓冲区高速缓存
处理某个查询时,Oracle 服务器进程会在数据库缓冲区高速缓存中查找它所需要的所有数据块的映像。如果未在数据库缓冲区高速缓存中找到数据块映像,服务器进程会从数据文
件中读取数据块,并在数据库缓冲区高速缓存中放置一个副本。由于对同一块的后续请求可能会在内存中找到相应的块,因此,这些请求可能不需要进行物理读取。
缓冲区高速缓存中的缓冲区可能处于以下四种状态之一:
• 已连接:可防止多个会话同时对同一数据块进行写操作。其它会话等待访问该块。
• 干净的:缓冲区现已解除连接,如果没有再次引用当前内容(数据块),该缓冲区是可以立即腾出的候选项。此时,不是缓冲区的内容已与磁盘中存储的数据块内容同步,就是缓冲区中包含数据块的一致读取(CR) 快照。
• 空闲或未使用:实例刚刚启动,缓冲区为空。此状态与“干净的”状态非常相似,不同之处在于缓冲区未曾使用过。
• 灰:缓冲区不再处于已连接状态,但是内容(数据块)已更改,DBWn必须先将内容刷新到磁盘,才能腾出缓冲区。
3、重做日志缓冲区
重做日志缓冲区是SGA 中的循环缓冲区,用于存放有关对数据库所做更改的信息。此信息存储在重做条目中。
重做条目包含重建(或重做)由DML、DDL 或内部操作对数据库进行的更改所需的信息。如果需要,将使用重做条目进行数据库恢复。
服务器进程更改缓冲区高速缓存时,系统会生成重做条目,并将生成的重做条目写入SGA 中的重做日志缓冲区。
重做条目占用缓冲区中连续的顺序空间。LGWR 后台进程将重做日志缓冲区写入磁盘上的活动重做日志文件(或文件组)中。
4、共享池
SGA 的共享池部分包含库高速缓存、数据字典高速缓存、SQL 查询结果高速缓存、PL/SQL 函数结果高速缓存、并行执行消息的缓冲区以及控制结构。
“数据字典”是数据库表和视图(它们包含有关数据库、数据库结构及其用户的参考信息)的集合。
在SQL 语句语法分析期间,Oracle DB 会频繁访问数据字典。该访问操作对于Oracle DB 的持续操作来说至关重要。
Oracle DB 对数据字典的访问十分频繁,因此在内存中指定了两个特殊的位置来存放字典数据。
一个区域称为“数据字典高速缓存”,也称为“行高速缓存”,因为它以行的形式存放数据,而不是以缓冲区的形式存放数据(缓冲区用于存放完整的数据块)。
内存中的另一个用于存放字典数据的区域称为“库高速缓存”。所有Oracle DB 用户进程都共享这两个高速缓存以便访问数据字典信息。
Oracle DB 使用共享SQL 区域(以及PGA 中保留的专用SQL 区域)来表示它所运行的每个SQL 语句。
Oracle DB 可识别两个用户执行相同SQL 语句的情况,从而为这些用户重用共享SQL 区域。
“共享SQL 区域”包含给定SQL 语句的语法分析树和执行计划。Oracle DB 通过为多次运行的SQL 语句使用一个共享SQL 区域来节省内存。当许多用户运行同一个应用程序时,同一SQL 语句通常会多次运行。对新的SQL 语句进行语法分析时,Oracle DB 会从共享池中分配内存,以便在共享SQL 区域中存储该语句。该内存的大小取决于语句的复杂性。
Oracle DB 处理PL/SQL 程序单元(过程、函数、程序包、匿名块和数据触发器)的方式与它处理单个SQL 语句的方式十分相似。Oracle DB 分配一个共享区域以存放程序单元在经过语法分析和编译之后的形式。Oracle DB 分配一个专用区域,以便存放特定于运行程序单元的会话的值,包括局部变量、全局变量和程序包变量(也称为“程序包实例化”),并且存放用于执行SQL 的缓冲区。如果多个用户运行同一个程序单元,则所有用户都使用同一个共享区域,但维护其各自专用SQL 区域的单独副本,以便存放特定于其自身会话的值。
PL/SQL 程序单元中包含的单个SQL 语句的处理方式与其它SQL 语句的处理方式类似。
无论这些SQL 语句在PL/SQL 程序单元中的来源如何,它们都使用共享区域来存放其语法分析表示,并且为运行语句的每个会话使用一个专用区域。
SQL 查询结果高速缓存和PL/SQL 函数结果高速缓存是Oracle Database 11g中新增的功能。
它们共享相同的基础结构,出现在相同的动态性能(V$) 视图中,并且使用所提供的同一程序包进行管理。
查询的结果和查询片段的结果可以高速缓存在“SQL 查询结果高速缓存”的内存中。这样,数据库可以在以后执行这些查询和查询片段时使用高速缓存结果进行回答。由于从SQL 查询结果高速缓存中检索结果要比重新运行查询快得多,因此将频繁运行的查询的结果缓存起来可以大大提高这些查询的性能。
如果计算的输入是PL/SQL 函数发出的一个或若干个参数化查询,则有时会使用该函数来返回计算结果。在某些情况下,这些查询访问很少更改的数据(与调用函数的频率相比)。
也可以在PL/SQL 函数的源文本中包括语法,以请求将函数结果缓存在“PL/SQL 函数结果高速缓存”中,并且在表列表中的表遇到DML 时清除高速缓存(以确保正确无误)。
5、分配和重用共享池中的内存
通常,共享池中的所有项(共享SQL 区域或字典行)都将一直保留,直到根据修改后的LRU(最近最少使用)算法对其进行刷新为止。如果必须在共享池中为新项提供空间,则会释放不经常使用的项的内存。使用修改后的LRU 算法可以让多个会话使用的共享池项在内存中长期保留(只要这些项还有用),即使最初创建该项的进程已终止。因此,最大限度减少了与多用户Oracle DB 系统相关联的SQL 语句的开销和处理。
在将SQL 语句提交到Oracle DB 以便执行时,将自动执行下列内存分配步骤:
1. Oracle DB 检查共享池以查看相同语句是否已存在共享SQL 区域。如果存在,则在执行该语句的后续新实例时使用此共享SQL 区域。如果某条语句没有共享SQL 区域,
则Oracle DB 会在共享池中分配一个新的共享SQL 区域。在以上任一情况下,用户的专用SQL 区域都与包含该语句的共享SQL 区域关联。
2. Oracle DB 分配一个代表会话的专用SQL 区域。该专用SQL 区域的位置取决于为会话建立的连接的类型。
注:可以从共享池中刷新共享SQL 区域,即使共享SQL 区域对应于某段时间内没有使用的打开游标时也是如此。如果随后使用这一打开的游标来运行其语句,则Oracle DB 会重
新对该语句进行语法分析,并在共享池中分配一个新的共享SQL 区域。
在以下情况下,Oracle DB 也会从共享池中刷新共享SQL 区域:
• 使用DBMS_STATS程序包更新或删除表、集群或索引的统计信息时,将从共享池中刷新满足以下条件的所有共享SQL 区域:这些共享SQL 区域包含引用了所分析的方案对象的语句。下次运行经过刷新的语句时,将在新的共享SQL 区域中对该语句进行语法分析,以反映方案对象的新统计信息。
• 如果在SQL 语句中引用了某个方案对象,并且随后以任何方式修改了该对象,则共享SQL 区域会失效(被标记为无效),下次运行该语句时必须重新进行语法分析。
• 如果更改数据库的全局数据库名,则会从共享池刷新所有信息。
• 管理员可以手动刷新共享池中的所有信息,以评估在实例启动(但未关闭当前实例)之后将达到的性能(与共享池有关的性能,而不是数据缓冲区高速缓存)。使用ALTER SYSTEM FLUSH SHARED_POOL语句可以执行此操作。
6、大型池
数据库管理员可以配置称为“大型池”的可选内存区,以便为以下对象提供大型内存分配:
• 共享服务器的会话内存和Oracle XA 接口(在事务处理与多个数据库交互时使用)
•I/O 服务器进程
• Oracle DB 备份和还原操作
通过从大型池中为共享服务器、Oracle XA 或并行查询缓冲区分配会话内存,Oracle DB 可以主要使用共享池来缓存共享SQL,并避免由于收缩共享SQL 高速缓存而导致的性能开销。
此外,用于Oracle DB 备份和还原操作、I/O 服务器进程以及并行缓冲区的内存以数百KB
的缓冲区进行分配。与共享池相比,大型池可以更好地满足此类大型内存请求。
大型池没有LRU 列表。它与共享池中的保留空间不同,后者与从共享池中分配的其它内存使用相同的LRU 列表。
7、Java 池和流池
存储JVM 中所有特定于会话的Java 代码和数据的服务器内存使用Java 池内存。Java 池内存的使用方式有多种,具体取决于Oracle DB 的运行模式。
Java 池指导统计信息提供了用于Java 的库高速缓存内存的相关信息,并预测Java 池大小的变化如何影响语法分析速率。当statistics_level设置为TYPICAL或更高值时,将在内部打开Java 池指导。关闭该指导时,将重置这些统计信息。
流池由Oracle Streams 独占使用。流池存储缓冲的队列消息,并且为Oracle Streams 捕获进程和应用进程提供内存。
除非对流池进行专门配置,否则其大小从零开始。当使用Oracle Streams 时,池大小会根据需要动态增长。