一:Oracle 内存结构由哪几部分组成?

1 User global area (UGA)
2 Program global area (PGA)
3 System global area (SGA)
4 软件代码区Software code areas

二:请分别介绍下UGA 、 PGA 、 SGA 、软件代码区?

1 UGA

UGA 是用户全局区,主要存放用户会话的相关信息,比如登录信息。
在会话的生命周期内,UGA 必须对数据库会话可用。
所以,在连接模式是专用服务器连接模式时,也就是一个会话对应一个连接,UGA 存储在 PGA 中。
但是在连接模式是共享服务器时,也就是多个会话对应一个连接,UGA 存储在 SGA 中的 large pool ,如果 large pool 空间不够, UGA 会存储在 shared pool 。大多情况下都使用专用服务器连接模式。

2 PGA

PGA(Process Global Area) 程序全局区, PGA 是一个非共享内存区域,它包含 Oracle 进程专用的数据和控制信息。在 Oracle 进程启动时创建 PGA 。由每个服务进程和后台进程专有,所有单个 PGA 的集合就是总实例 PGA 大小。
PGA 内容:
PGA 主要有两个区域, 私有SQL 区域、 SQL 工作区域。
私有SQL 区域存储 SQL 的绑定变量值、查询执行状态信息,客户端进程负责管理私有 SQL 区域。分配的私有 SQL 区域的数量受初始化参数 OPEN_CURSORS 的限制。
SQL 工作区主要用于排序操作、 Hash 连接、位图合并连接时使用的内存。
比如 order by 、 group by 等操作。
PGA 管理:
在Oracle8i 中, PGA 调整非常复杂,要调整 SORT_AREA_SIZE 、 HASH_AREA_SIZE 、 BITMAP_MERGE_AREA_SIZE 、 CREATE_BITMAP_AREA_SIZE 等参数。在 ORACLE9I 以后,只需要调整 PGA_AGGREGATE_TARGET ,这个值是个软限制,比如设置大小 2G ,只是一个目标值,实际上 PGA 大小可以超过 2G 。在 12C 开始引入 PGA_AGGREGATE_LIMIT 参数限制 Oracle 实例 PGA 使用内存的上限,如果超过限制就采取终止会话的方式来降低 PGA 内存的使用量。

3 SGA

系统全局区域(SGA) ,是一组共享内存结构,所有服务器和后台进程共享 SGA 。
与Oracle 后台进程一起构成数据库实例。
可以在V$SGASTAT 视图中查询关于 SGA 组件的信息。最重要的 SGA 组件如下 :

  • Database Buffer Cache
  • Shared Pool
  • Redo Log Buffer
  • In-Memory Area
  • Large Pool
  • Java Pool
  • Fixed SGA
  • 可选的与性能相关的 SGA 子区域
    (1)Database Buffer Cache
    数据库缓冲区缓存,也称为缓冲区缓存,是数据文件上的数据块在内存中的副本。主要是为了在内存中进行高速的数据查找和更新, 尽量减少磁盘的 IO 操作。也是 SGA 中占比比较大的一块内存区域。用户访问 DB Cache 的数据比访问磁盘上的数据速度更快数 ( 内存的读取效率是磁盘读取效率约 14000 倍 ) ,因此应用系统应该尽可能多地从 DB Cache 中访问数据。在大多数情况下, DB Cache 的命中率越高,访问性能就越好。
    缓冲池包括:default 默认池、 keep 保留池、 recycle 回收池
    Buffer Cache 管理:
    通过三条链表进行管理:HASH 链表、检查点队列链表、 LRU 链表
    HASH 链表
    HASH 链表的作用是通过 HASH 算法 ( 消耗 CPU 资源 ) ,提高 DB Cache 中数据块的定位速度。也就是逻辑读。
    比如,根据需要访问块的块号、文件号计算HASH 值,在通过 HASH 值找到对应的 HASH Bucket, 搜索 Buckect 后的链表,找到目标 BH(Buffer Header), 通过 BH 找到 BA(Buffer Address) ,按照 BA 访问具体的 Buffer, 这个就是逻辑读的过程。
    检查点队列链表(CKPT-Q)
    主要用于记录脏块。
    Buffer Cache 其实就是磁盘数据文件的缓存,以修改块的操作为例,如 update ,只是修改 Buffer Cache 中的 Buffer, 修改完成后 ,update 操作就算完工了。这样 Buffer 中的数据和磁盘中的 block 就不一致了,这样的 Buffer 就是脏 Buffer ,脏块由 DBWR 进程统一写磁盘,但是 Buffer Cache 通常很大,有几万或几十万 Bufeer ,怎么在 Buffer Cache 中找到哪些是脏 Buffer 呢,这就需要一个链表,将所有脏 Buffer 都串起来, DBWR 写脏块时,就是按照这个串起来的链表的顺序来写,这样的脏链表有两个,一个是 LRUW ,另一个是 CKPT-Q。 在 buffer cache 中,修改完数据后,会将对应的数据块加入到检查点队列 (CKPT-Q) 。
    LRU 链表 ( 最近最少使用链表 )
    物理读时,服务器进程将数据块从数据文件读进Buffer Cache 中,假如 Buffer Cache 有 10000 个 Buffer ,那么进程应该覆盖哪个 Buffer 呢?
    简单说,就是进程将数据块读进Buffer Cache 的什么地方。
    答案是,覆盖最不常用的Buffer , LRU 主要就是解决如何快速找到最不常用的 Buffer 。
    在Oracle 8i 之前, LRU 算法 是 ,DB Cache 在 LRU 上是会移动的,常用的缓冲会被换到 LRU 的热端,不常用的缓冲会被挤到 LRU 的冷端,一般来说会话分配 Cache 时,会从 LRU 的冷端开始查找。这种 LRU 算法会产生性能瓶颈 。
    从 Oracle 8i 开始, LRU 的算法有所改进, LRU 链上的缓冲不再需要移动了,而是通过 tch 计数器大小值来判断某个数据块是否为热块。
    (2)Redo Log Buffer
    重做日志缓冲区是SGA 中的一个循环缓冲区,它存储描述数据库更改的重做条目。
    重做记录是一种数据结构,它包含重做DML 或 DDL 操作对数据库所做更改所需的信息。数据库恢复将重做项应用于数据文件以重构丢失的更改。
    LGWR 按顺序将数据块写入磁盘,而 DBW 将数据块分散写入磁盘。分散写比顺序写要慢得多。因为 LGWR 允许用户避免等待 DBW 完成缓慢的写操作,所以数据库提供了更好的性能。
    LOG_BUFFER 初始化参数指定 Oracle 数据库在缓冲重做条目时使用的内存量。与其他 SGA 组件不同,重做日志缓冲区和固定 SGA 缓冲区不会将内存分成颗粒。
    (3)Shared Pool
    相比于Buffer Cache ,共享池中的内容可谓是杂乱无章。 Oracle 基本上将不能放进 Buffer Cache 中的数据都扔进了共享池,使得共享池的分配和释放极为频繁。
    共享池中最基本的内存分配单元成为Chunk, 相当于 Buffer Cache 中的 Buffer 或块的概念。
    Chunk 的大小极不统一,最新的 Chunk 可以只有十来个字节,最大的 Chunk 有几十兆甚至几百兆。基本内存单元大小的不统一,再加上频繁进行分配、释放操作,使共享池中极易产生内存碎片。总的来说,共享池是 Oracle 中最复杂的内存池。
    包括以下内容:
    Library Cache
    Data Dictionary Cache
    Server Result Cache
    Reserved Pool
    1 Library Cache
    库缓存 主要 存储 用户提交的 SQL 语句、SQL 语句相关解析数、 SQL 执行计划、 PL/SQL 程序块等 。
    2 Data Dictionary Cache
    dictionary cache 里存放了数据字典的内存结构,包括 表的定义、Storage 信息、用户权限信息、约束定义、表的统计信息等。 SQL 语句解析期间频繁地访问数据字典。构造 dictionary cache 的目的是为了加快 SQL解析过程中语义解析 的速度。
    数据字典缓存也被称为行缓存(Row Cache ),因为它是以记录行为单元存储数据的,而不像 Buffer Cache 是以数据块为单元存储数据。
    3 Server Result Cache
    服务器结果缓存是共享池中的内存池。与缓冲池不同,服务器结果缓存保存结果集,而不是数据块。
    执行查询时,数据库将确定查询结果是否存在于查询结果缓存中, 如果结果存在,那么数据库将从缓存中检索它,而不是执行查询。缓存使数据库能够避免重新读取数据块和重新计算结果的昂贵操作。
    4 Reserved Pool
    保留池是共享池中的一个内存区域,Oracle 数据库可以使用它来分配大的连续内存块。
    如果Oracle 解析一个 PL/SQL 程序单元,也需要从共享池中分配内存给这些程序单元对象。由于这些对象本一般比较大(如包),所以分配的内存空间也相对较大。系统经过长时间运行后,共享池可能存在大量内存碎片,导致无法满足对于大块内存段的分配。为了使有足够空间缓存大程序块, Oracle 专门从共享池内置出一块区域来来分配内存保持这些大块。
    数据库以块的形式从共享池分配内存。分块允许将大对象( 超过 5 KB) 加载到缓存中,而不需要单个连续区域。通过这种方式,数据库减少了内存碎片的产生。
    (4)Large Pool
    大池是一个可选的内存区域,用于比共享池更大的内存分配。
    大池可以为以下情况提供大内存分配:
    用于共享服务器和 Oracle XA 接口 ( 用于事务与多个数据库交互 )
    并行执行中使用的消息缓冲区
    用于恢复管理器 (RMAN) I/O 从属的缓冲区
    (5)Java Pool
    Java 池是存储 Java 虚拟机 (JVM) 中所有特定于会话的 Java 代码和数据的内存区域。此内存包括在调用结束时迁移到 Java 会话空间的 Java 对象。
    对于专用服务器连接,Java 池包括每个 Java 类的共享部分,包括方法和只读内存 ( 如代码向量 ) ,但不包括每个会话的 Java 状态。
    (6) 可选的与性能相关的SGA 子区域
    一些SGA 子区域只针对特定的性能特性启用。本节包含以下主题 :
    In-Memory Area
    Memoptimize Pool
    In-Memory 是12C 开始,在 SGA 中新增加的内存区域,可以实现表数据按列存储;
    In-Memory 并没有取代传统的 Buffer Cache ,二者并存在 SGA 中。列式存储在访问多行、少列情况下性能更优。
    memoptimize pool 大小通过MEMOPTIMIZE_POOL_SIZE 设置,其中存储着启用了 fast lookup 表的散列索引。
    从18c 开始支持 Memoptimized Rowstore ,可用于提高查询性能。针对频繁基于主键查询的 SQL 语句的性能提高十分明显。可以通过 CREATE TABLE 或 ALTER TABLE … MEMOPTIMIZE FOR READ 语句来启用表的 fast lookup 。
    (7)软件代码区概述
    软件代码区是存储正在运行或可以运行的代码的内存的一部分。Oracle 数据库代码存储在一个软件区域中,这个软件区域通常比用户程序的位置更具排他性和受保护性。 软件区域的大小通常是静态的,只有在软件更新或重新安装时才会改变。这些区域所需的大小因操作系统而异。
    软件区域是只读的,可以安装共享的,也可以安装非共享的。有些数据库工具和实用程序( 如 Oracle Forms 和 SQL*Plus) 可以安装为共享的,但有些则不能。在可能的情况下,数据库代码是共享的,这样所有用户都可以访问它,而不需要在内存中有多个副本,从而减少了主内存,并在总体上提高了性能。如果在同一台计算机上运行,数据库的多个实例可以将相同的数据库代码区域用于不同的数据库。
    转载自chenoracle
最后修改:2022 年 02 月 27 日
如果觉得我的文章对你有用,请随意赞赏