目录
一、 SGA 的设计目标与核心思想
- 共享 (Shared):
- 核心设计理念: SGA 被数据库实例的所有服务器进程(Server Processes)共享访问。这是 Oracle 实现高并发、高性能的基础。
- 解决的问题: 避免每个用户进程在操作数据时都需要从磁盘重复读取相同的数据块或 SQL 语句信息,极大减少 I/O 和重复计算。
- 全局 (Global):
- 它是整个数据库实例的单一、中心化的内存区域。所有连接到该实例的会话看到的是同一份 SGA 内容(当然,访问权限和数据可见性受事务隔离级别控制)。
- 解决的问题: 保证数据在内存中的一致性视图。所有进程看到的是同一份数据字典缓存、同一份库缓存(共享 SQL/PLSQL 区域)、同一份数据块缓冲区。
- 缓存 (Cache):
- SGA 的主要作用是作为磁盘数据的缓存和共享执行信息的缓存。
- 解决的问题: 磁盘 I/O 是数据库操作中最慢的环节。SGA 将频繁访问的数据块(Data Blocks)、数据字典信息(Dictionary Cache)、SQL/PLSQL 执行计划(Library Cache)、重做日志记录(Redo Log Buffer)等缓存在速度极快的内存中,显著提升访问速度。
- 高效通信:
- 后台进程(如 DBWn, LGWR, CKPT)与服务器进程之间通过 SGA 进行高效的通信和数据交换,无需复杂的进程间通信机制。
- 持久化支持:
- 虽然 SGA 本身是内存结构(易失性),但其设计(特别是 DBWn 和 LGWR 进程)确保了数据的持久性(ACID 中的 D)。修改的数据最终会写入数据文件,事务日志会写入在线重做日志文件。
二、 SGA 的核心原理
- 内存工作集: SGA 是 Oracle 实例在内存中维护的数据库活动状态的工作集。它包含了当前最活跃、最需要快速访问的数据和控制信息。
- LRU 算法及其变种: 缓冲区(Buffer Cache, Shared Pool)的管理核心是最近最少使用 (Least Recently Used, LRU) 算法或其优化变种(如 Touch Count, KEEP/RECYCLE 池)。当需要空间缓存新内容时,优先淘汰最久未被访问或访问频率最低的条目。
- 闩锁 (Latch) 与互斥体 (Mutex): 由于 SGA 是共享资源,多个进程并发访问时需要通过轻量级的同步机制(Latch/Mutex) 来保护其内部数据结构的完整性和一致性。获取 Latch/Mutex 的争用是性能调优的重要关注点。
- 检查点 (Checkpoint): DBWn 进程根据检查点事件将脏缓冲区 (Dirty Buffers)(已被修改但尚未写入磁盘的数据块)写入数据文件。检查点保证了内存中的数据与磁盘文件在某个时间点的一致性,并缩短实例恢复所需的时间。
- 日志先行 (Write-Ahead Logging, WAL):
- 核心原理: 任何对数据块的修改产生前,必须先在重做日志缓冲区中生成对应的重做记录 (Redo Record)。
- LGWR 写盘: LGWR 进程负责将重做日志缓冲区的内容尽快写入在线重做日志文件。这个写操作通常在事务提交前或缓冲区满 1/3、每 3 秒、DBWn 写脏块前等时机触发。
- 解决的问题: 保证即使在实例崩溃的情况下,已提交事务的修改也能通过重做日志进行恢复(前滚),未提交事务的修改可以撤销(回滚)。这是实现事务 ACID 属性中持久性 (Durability) 的关键。
三、 SGA 的主要组件详解
-
数据库缓冲区高速缓存 (Database Buffer Cache / DB Cache)
- 功能: 缓存从数据文件中读取的数据块副本。这是 SGA 中通常最大的组件,对性能影响最大。
- 结构:
- 缓冲区 (Buffers): 固定大小的内存块(与数据库块大小一致,如 8KB),用于存放单个数据块。
- 缓冲区头 (Buffer Headers): 包含缓冲区状态信息(如脏/干净、Pin状态、访问时间、所属数据文件/块号、指向实际缓冲区的指针等)。
- Hash Bucket / Cache Buffers Chains: 通过 Hash 算法快速定位某个特定数据块(
<file#, block#>)是否在缓存中及其位置。访问这些链需要获取 Cache Buffers Chains Latch。 - LRU / LRUW 链表: 管理缓冲区的使用状态和淘汰顺序。干净的、可重用的缓冲区主要在 LRU 链表上;脏缓冲区主要在 LRUW (Write) 链表上等待 DBWn 写入。
- 状态:
- 干净 (Clean): 缓冲区内容与磁盘上数据文件中的块一致。
- 脏 (Dirty): 缓冲区内容已被修改,与磁盘上的块不一致,需要由 DBWn 写入数据文件。
- 空闲 (Free): 缓冲区为空,可用于存放新读取的块。
- Pin: 进程正在访问该缓冲区,防止其被移出缓存或被覆盖。
- 工作方式:
- 读: 进程需要读取数据块时,先检查 DB Cache。命中(找到)则直接读取内存(逻辑读);未命中(cache miss)则触发物理读,从磁盘读取块到空闲或可替换的缓冲区中,再读取。
- 写: 进程修改数据块在 DB Cache 中的副本,使其变为脏。写操作本身只发生在内存,DBWn 负责异步将脏块写回磁盘。
- 优化:
- 多缓冲池:
DB_KEEP_CACHE_SIZE,DB_RECYCLE_CACHE_SIZE,DB_nK_CACHE_SIZE(用于非标准块大小表空间)。将对象分配到不同的池(如频繁访问的小表放 KEEP,全表扫描大对象放 RECYCLE)可以优化缓冲区利用率,避免大扫描冲刷掉热点小表。 - 直接路径读 (Direct Path Read): 某些操作(如并行查询、大表全扫)可能绕过 DB Cache 直接读取数据到 PGA,避免污染缓存。可通过优化 SQL 或调整参数控制。
- 多缓冲池:
-
重做日志缓冲区 (Redo Log Buffer)
- 功能: 临时存储由服务器进程生成的重做条目 (Redo Entries)。记录了对数据块所做的所有更改向量 (Change Vectors)。这是保证数据持久性和可恢复性的关键组件。
- 结构: 一个循环使用的环形缓冲区 (Circular Buffer)。
- 工作方式:
- 服务器进程修改数据块前,先在内存中生成重做条目,并将其复制到重做日志缓冲区。
- LGWR 进程: 负责将重做日志缓冲区的内容写入在线重做日志文件 (Online Redo Log Files)。触发条件包括:
- 事务提交 (
COMMIT)。 - 重做日志缓冲区满 1/3。
- 每隔 3 秒。
- DBWn 进程需要写入脏块前(确保先有日志)。
- 检查点发生。
- 事务提交 (
- 写入后,缓冲区中被写入的部分即可被新条目覆盖。
- 重要性: 实现了 Write-Ahead Logging (WAL) 协议。先写日志,后写数据。保证在系统故障时,即使内存中修改的数据丢失,也能利用重做日志文件重做已提交的事务。
- 优化: 主要避免
log buffer space等待事件。适当增大LOG_BUFFER(通常较小,1MB 到几十MB),确保 LGWR 能及时写盘。频繁的小提交会增加 LGWR 负担。
-
共享池 (Shared Pool)
- 功能: 缓存可被所有会话共享的 SQL 和 PL/SQL 代码、执行计划、数据字典信息等。目标是减少硬解析,提高代码执行效率。
- 核心组件:
- 库高速缓存 (Library Cache):
- 存储解析后的 SQL 语句、PL/SQL 代码块(过程、函数、包、触发器)及其执行计划。
- 结构: 基于 Hash 桶管理。存储单元称为游标 (Cursor),包含 SQL 文本、执行计划、优化器环境、绑定变量类型等。
- 工作方式:
- 软解析 (Soft Parse): 新 SQL 提交,库缓存中已存在完全匹配(SQL 文本、对象定义、优化器模式、绑定变量类型等完全相同)的游标及其有效执行计划,则直接复用。性能最佳。
- 硬解析 (Hard Parse): 未找到匹配游标。需要执行完整解析过程:语法语义检查(依赖数据字典缓存)、对象权限验证、优化器生成执行计划。消耗大量 CPU 和 Latch 资源,应尽量避免。
- 重要概念:
- 绑定变量 (Bind Variables): 使用占位符
:var代替 SQL 文本中的字面值。极大提高游标共享性,减少硬解析。是优化库缓存的关键实践。 - 游标失效 (Invalidation): 当 SQL 依赖的对象(如表结构、索引、统计信息)发生变化时,相关游标会被标记为无效。下次执行时需重新硬解析。
- 绑定变量 (Bind Variables): 使用占位符
- 数据字典高速缓存 (Dictionary Cache / Row Cache):
- 缓存数据库的元数据 (Metadata):表、列、索引、用户、权限、约束等数据字典表(如
tab$,col$,user$)的信息。 - 工作方式: 服务器进程需要元数据时(如解析 SQL 验证表名、列名、权限),先查此缓存。未命中则需从磁盘读取系统表空间(如 SYSTEM, SYSAUX)的数据字典基表,代价较高。
- 重要性: 几乎所有 SQL 和 PL/SQL 操作都依赖数据字典信息。高效的字典缓存能显著提升解析效率。
- 缓存数据库的元数据 (Metadata):表、列、索引、用户、权限、约束等数据字典表(如
- 库高速缓存 (Library Cache):
- 优化:
- 使用绑定变量。
- 避免频繁 DDL 操作(导致游标失效)。
- 合理配置
SHARED_POOL_SIZE(或自动管理)。 - 监控
library cache lock/pin、row cache lock等等待事件和reloads,invalidations等指标。 - 对于大型 PL/SQL 包,可考虑
DBMS_SHARED_POOL.KEEP固定到内存避免被淘汰。
-
大池 (Large Pool)
- 功能: 为需要大块、连续内存分配的操作提供专用区域,减轻共享池的压力和碎片化。可选组件,但某些功能必需。
- 主要使用者:
- 共享服务器 (Shared Server / MTS) 的会话内存 (UGA)。
- 并行查询 (Parallel Query) 的进程间通信 (Pnnn slaves)。
- RMAN 备份与恢复的 I/O 缓冲区。
- I/O 从属进程 (I/O Slaves) 的缓冲区。
- 优化: 如果使用上述功能且观察到共享池存在大量
free memory等待或large pool不足等待 (kgh: no space),应配置LARGE_POOL_SIZE。
-
Java 池 (Java Pool)
- 功能: 为在数据库中运行的 Java 代码 (Java Stored Procedures, JVM) 提供内存。存储 Java 虚拟机 (JVM) 的会话状态、Java 对象、Java 执行代码等。
- 重要性: 仅当数据库中使用 Java 相关功能(如 Java 存储过程)时才需要关注。否则可以保持默认或较小大小。
- 优化: 通过
JAVA_POOL_SIZE配置。监控 Java 相关的内存使用和性能。
-
流池 (Streams Pool) - (10g+)
- 功能: 专门用于 Oracle Streams 或 GoldenGate(早期集成时)功能的缓冲队列。存储捕获的变更、传播的消息和应用的消息。
- 重要性: 仅在启用了 Oracle Streams 复制功能时才需要配置。
- 优化: 通过
STREAMS_POOL_SIZE配置。根据 Streams 负载调整。
-
固定 SGA (Fixed SGA)
- 功能: SGA 内部的一个小型、固定大小的区域。存储指向 SGA 其他组件的指针、后台进程和服务器进程通信所需的状态信息、各种数据库实例级别的原子变量(如 SCN)等。类似于 SGA 的“控制中心”或“元数据区”。
- 特点: 大小由 Oracle 内部决定,DBA 无法直接配置。通常很小(几百KB到几MB)。
四、 SGA 的内存管理
- SGA 大小配置:
- 手动管理 (Manual SGA Management - 9i 及之前):
- 分别设置各个主要组件的大小:
DB_CACHE_SIZE,SHARED_POOL_SIZE,LARGE_POOL_SIZE,LOG_BUFFER,JAVA_POOL_SIZE等。 - 需要 DBA 仔细评估和调整,容易造成资源分配不均或浪费。
- 分别设置各个主要组件的大小:
- 自动共享内存管理 (Automatic Shared Memory Management - ASMM - 10g & 11g):
- 设置一个总目标
SGA_TARGET。 - Oracle 自动在主要组件(DB Cache, Shared Pool, Large Pool, Java Pool, Streams Pool)之间动态调整内存分配。
- DBA 可以为某些组件设置最小值 (
_MIN_SIZE)。 - 注意:
LOG_BUFFER和KEEP/RECYCLE/nK Cache仍需手动设置。
- 设置一个总目标
- 自动内存管理 (Automatic Memory Management - AMM - 11g+):
- 设置一个总目标
MEMORY_TARGET。 - Oracle 自动在 SGA (
SGA_TARGET) 和 PGA (PGA_AGGREGATE_TARGET) 之间,以及 SGA 内部各组件之间动态调整内存分配。 - 最简化管理,适合大多数场景。但某些极端性能场景可能需要手动微调 SGA。
- 设置一个总目标
- 粒度 (Granules):
- SGA 组件内存的分配和回收以粒度 (Granule) 为单位。粒度大小取决于总的 SGA 大小(通常 4MB, 8MB, 16MB, 32MB, 64MB)。
V$SGAINFO可查看。 - 组件大小必须是粒度的整数倍。
- SGA 组件内存的分配和回收以粒度 (Granule) 为单位。粒度大小取决于总的 SGA 大小(通常 4MB, 8MB, 16MB, 32MB, 64MB)。
- 手动管理 (Manual SGA Management - 9i 及之前):
- SGA 的动态调整:
- 在 ASMM 或 AMM 下,Oracle 根据工作负载自动在组件间调整内存。
- 即使手动管理,
DB_CACHE_SIZE,SHARED_POOL_SIZE,LARGE_POOL_SIZE,JAVA_POOL_SIZE,STREAMS_POOL_SIZE参数通常可以在实例运行期间 (ALTER SYSTEM SET ... SCOPE=MEMORY|SPFILE;) 动态调整(增大或减小),无需重启。LOG_BUFFER和KEEP/RECYCLE/nK Cache通常需要重启生效。
- SGA 的分配与初始化:
- 当数据库实例启动 (
STARTUP) 时,根据参数文件 (spfile或pfile) 中的设置分配 SGA 内存。 - 分配的是共享内存段 (Shared Memory Segments),操作系统可见。
- 在 ASMM/AMM 下,
SGA_TARGET/MEMORY_TARGET是初始分配大小,内部组件根据需要增长(在目标范围内)。
- 当数据库实例启动 (
五、 SGA 的监控与性能优化关键点
-
关键动态性能视图 (V$ Views):
V$SGA/V$SGAINFO: SGA 总大小、组件大小、粒度信息。V$SGASTAT: SGA 内部各子池/区域的详细统计信息(已用、空闲、保留内存等)。V$BUFFER_POOL/V$DB_CACHE_ADVICE: Buffer Cache 各池状态、命中率预测建议。V$LIBRARYCACHE: 库缓存命中率 (gethitratio)、重载 (reloads)、失效 (invalidations)。关注reloads和pins。V$ROWCACHE: 数据字典缓存命中率 (getmisses/ (gets+getmisses))。关注高getmisses。V$SYSSTAT: 系统级统计,如session logical reads(逻辑读),physical reads(物理读),parse count (total/hard),execute count。计算 Buffer Cache Hit Ratio =1 - (physical reads / (session logical reads - physical reads direct - physical reads direct (lob)) )。注意:命中率在现代系统中有局限性,需结合等待事件分析。V$SESSION_WAIT/V$SYSTEM_EVENT: 关键等待事件:buffer busy waits/read by other session: 热块争用。cache buffers chains latch: Hash Chain 争用(可能是热块或 SQL 效率低导致访问过多块)。library cache: mutex X/library cache lock/library cache pin: 库缓存争用(硬解析多、未用绑定变量、游标失效频繁)。log buffer space: 重做日志缓冲区太小或 LGWR 写盘慢。free buffer waits: DBWn 写脏块速度跟不上需求(Buffer Cache 太小?脏块太多?I/O 慢?)。enq: TX - row lock contention: 行锁争用(应用逻辑问题)。latch free: 泛指闩锁争用,需结合具体 Latch Name (V$LATCH) 分析。
-
优化方向:
- 减少物理 I/O: 增大 Buffer Cache (或优化使其更有效 - KEEP/RECYCLE池, 优化 SQL 减少访问块数),使用更快的存储。
- 减少硬解析: 强制使用绑定变量,使用游标共享 (
CURSOR_SHARING- 谨慎),避免频繁 DDL,调整SESSION_CACHED_CURSORS,OPEN_CURSORS。 - 缓解争用:
- 热块: 反向键索引、哈希分区、
PCTFREE/INITRANS、应用设计分散热点。 - Latch/Mutex 争用: 优化 SQL(减少逻辑读/物理读)、绑定变量(减少库缓存争用)、调整
_SPIN_COUNT(谨慎)、升级或打补丁。
- 热块: 反向键索引、哈希分区、
- 合理配置大小:
- 利用 ASMM/AMM 简化管理。
- 监控建议(如
V$DB_CACHE_ADVICE,V$SHARED_POOL_ADVICE)。 - 确保
LARGE_POOL_SIZE足够(如果使用相关功能)。 LOG_BUFFER不宜过大(通常几MB到几十MB),重点是确保 LGWR 能及时写盘。
- SQL 优化: 这是最根本、最有效的优化手段! 低效的 SQL 会浪费大量 SGA 资源(缓存无效数据、增加解析负载、引起热块和 Latch 争用)。使用
EXPLAIN PLAN,SQL Trace (10046),AWR/ASH报告分析优化 SQL。
六、 总结
SGA 是 Oracle 数据库实例的心脏,是数据库高性能、高并发、一致性和可恢复性的基石。它的设计核心是共享、全局、缓存。
- DB Cache 缓存数据块,减少磁盘 I/O,通过 LRU 和 DBWn 管理。
- Redo Log Buffer 记录变更,通过 WAL 协议和 LGWR 保证持久性。
- Shared Pool (Library Cache + Dictionary Cache) 缓存 SQL/PLSQL 代码和执行计划、元数据,核心是减少硬解析,依赖绑定变量。
- Large/Java/Streams Pools 为特定功能提供大内存或专用内存。
- Fixed SGA 存储关键控制信息。
SGA 调优的本质是平衡:
- 内存与磁盘: 最大化缓存命中率,减少物理 I/O。
- 共享与争用: 利用共享减少重复工作,但需管理好并发访问的同步开销(Latch/Mutex)。
- 解析与执行: 减少昂贵的硬解析(CPU/Latch),让资源更多用于真正的 SQL 执行。
- 空间与时间: 分配足够内存容纳工作集,但避免过度分配浪费资源。
评论区