• SGA_MAX_SIZE参数

SGA由一些特定的内存部件组建构成,这些内存组件是为了满足特定的内存分配需求的内存池。内存分配和回收的单位是granules。Oracle数据库用内部每个内存组件包含的granules的个数来跟踪SGA。

Granule的大小由整个SGA的大小决定。在大多数平台中,如果整个SGA的大小小于1GB那么granule的大小为4M,大的SGAs的granule为16M。还有一些granule的大小与平台有关。例如,在32位的Windows中,当SGAs的大于1GB时granule的大小为8M。

Oracle数据库可以限制SGA中虚拟内存的使用量。Oracle数据库用最小的内存启动,它允许扩展SGA内存组件的大小是实例使用更多的内存,SGA能达到的最大值由参数SGA_MAX_SIZE限制。如果初始化参数文件或服务器参数文件中SGA_MAX_SIZE的设置的值小于SGA中所有内存组件的和,那么数据库将忽略SGA_MAX_SIZE的设置。

从性能方面考虑,整个SGA适合放在实内存中。如果用虚拟内存来存放部分SGA的话,整个数据库的性能会明显下降。因为部分SGA是由操作系统分页的(从磁盘读或写)。

SGA的大小是由一些初始化参数决定的,下面几个参数对SGA大小有重要的影响:

参数描述
DB_CACHE_SIZE标准数据块缓存的大小
LOG_BUFFER分配给redo log buffer的字节数
SHARED_POOL_SIZE为共享SQL和PL/SQL语句服务的内存字节数
LARGE_POOL_SIZElager pool的大小:默认为0
JAVA_POOL_SIZEJava pool的大小

早期的数据库版本中,数据库管理员需要手动的设置初始化参数来指定不同的SGA内存组件的大小,这些内存参数包括SHARED_POOL_SIZE,DB_CACHE_SIZE,JAVA_POOL_SIZE和LARGE_POOL_SIZE。为了方便管理,oracle推出了自动内存管理参数的功能,DBA只需要通过SGA_TARGET参数指定SGA的总大小,Oracle数据库将自动的在众多子内存组件中分发内存保证内存的高效使用。

当启用自动SGA内存管理后,不同SGA组件的大小将根据实际的负载来自动调整。数据库将自动的根据内存需要在各个内存组件之间合理的分配内存,保证SGA最大限度的被使用。

假设手动配置1GB给SGA使用并通过以下参数设置内存组件的大小:

SHARE_POOL_SIZE=128M

DB_CACHE_SIZE=896M

如果一个应用试图从共享池中得到超过128M的内存,这时候会报共享内存已经被耗尽的错误。这时候缓存中有空闲内存,但是这些内存不能被共享池访问。针对这个问题你需要手动的调整缓存和共享池的大小。

在自动SGA管理模式下,你只需要简单的将SGA_TARGET参数的值设置为1GB。如果一个应用需要更多的共享池内存时,它可以自动的向缓存请求所需内存。

通过设置一个简单的参数管理内存极大的方便了数据库的管理。你只需要指定实例需要的使用的SGA的大小而不需要指定每个内存组件的值。数据库一不会产生内存耗尽的错误除非系统真的内存耗尽了。

自动内存管理能提高运行效率,它不需要任何附件的资源和手动的调整。在手动内存模式下,编译过的SQL语句可能因为共享池固定的值经常被移出。当自动内存管理启用后,内部的调优双方会监控系统的性能,根据需求自动调整共享池的大小。

    • SGA_TARGET参数

SGA_TARGET初始化参数反应了整个SGA的大小,它包含一些几个内存组件:

  • Fixed SGA and other internel allocation needed by the oracle Database instance
  • The log buffer
  • The shared pool
  • The Java pool
  • The buffer cache
  • The keep and recycle buffer caches(if specified)
  • Nonstandard block size buffer caches(if specified)
  • The stream pool

这里重点指出SGA_TARGET涵盖了这个SGA的内存大小,相比较的是早期版本中内部和固定的SGA加到上配置内存参数的和中。因此,SGA_TARGET使你能够精确的管理数据库分配给共享内存区域的大小。如果在数据库启动时SGA_TARGET设置的值大于SGA_MAX_SIZE设置的值,后者将会被忽略而自动的适应SGA_TARGET。

    • 自动管理的SGA组件

当你设置好SGA_TARGET的值后,Oracle数据库自动的给常见的内存组件分配内存空间,这些组件包括:

  • The Java pool
  • The large pool
  • The buffer cache
  • The stream pool
  • The shared pool

你不需要直接的设置这些内存组件的值。这些内存组件的初始化参数默认为0.当一个组件需要内存时,它会使用内部的自动调整机制从其他组件获得内存。之中转换机制是系统自动完成的,不需要人工参与。

这种内存自动分配的动作被oracle数据库实例监控。Oracle实例运用内部的视图和数据来决定最佳的内存分别方式。当负载发生变化时,oracle会重新分发内存来达到最佳的性能。为了计算最佳的内存分配方式,数据库运用一个算法来考虑长期和短期的趋势。

  • 手动管理的SGA组件

有些SGA组件的大小不能通过自动管理的方式来调整。如果应用需要的话,管理员需要明确的制定这些组件的大小。这些组件包括:

  • Keep/Recycle buffer caches(controlled by DB_KEEP_CACHE_SIZE and DB_RECYCLE_CACHE_SIZE
  • Additional buffer caches for non-standard block sizes(controlled by DB_nK_CACHE_SIZE,n={2,4,8,16,32})

这些组件的大小需要管理员手动的定义与之关联的初始化参数。当然,这些参数可以随时通过Enterprise Manager或通过在命令行中通过ALTER SYSTEM语句改变。

当然,手工指定大小的内存组件消耗的内存会减少能自动内存调整的内存组件可用的内存量。

看如下配置:

SGA_TARGET=256M

DB_8K_CACHE_SIZE=32M

因此实例只有224MB(256-32)可用于自动内存分配。

  • 自动调整值的永久性

如果你使用的SPFILE,当数据库关闭时它会自动记住此时每个自动调整贵的内存组件的大小。这的话避免了系统每次启动时都要再次了解系统的负载特点。他可用从实例关闭的时候记录的大小开始。

  • 添加Granules和跟踪内存组件的大小

数据库管理员可用通过ALTER SYSTEM语句来修改初始化参数从而修改对应的SGA内存组件的大小。Oracle数据库总是以系统中Granule大小的倍数来增加或减少内存,只要没有达到SGA_MAX_SIZE的值,Oracle数据库就可以分配内存。

SGA中当前各组件中Granule的大小可以通过查询V$SGAINFO获得。每个组件的大小和最后一次重新分配大小的操作时间和操作类型可以通过查询V$SGA_DYNAMIC_COMPONENTS视图获得。Oracle数据库维护了一个可以保存近400次组件重新分配大小操作的循环空间。你可以查询VRSGA_RESIZE_OPS视图来查看这个循环空间。

  • 数据缓冲区

数据库缓冲区里保存着从数据文件的数据块复制的数据。所有并发连接到数据库的用户共享数据库的数据缓冲区

数据缓冲区和贡献的SQL缓存逻辑的分为多个集合。这种多集合的组织方式减少了多进程系统中对缓冲区得争用。

  • 数据缓冲区的组织

缓存中的缓冲区以两种链表组织:write list和least recently used(LRU)list。Write list包含dirty buffer,dirty buffer中包含已经被修改但是还没有来得及写入磁盘的数据。LRU List中包含free buffers,pinned buffers和还没有移动到write list中的dirty buffer。Free buffers不包含任何有用数据的能被使用。Pinned buffers是正在被访问的缓存。

当一个oracle进程访问buffer时,这个进程将buffer移动到LRU list中的most recently used(MRU)的尾部。随着越来越多的buffers移动到LRU list中的MRU的尾部,dirty buffers逐渐向LRU list中的LRU的尾部移动。

当Oracle的用户进程查询一个特定的数据时,进程首先到buffer cache里查找,如果在缓存里找到了这个数据(cache hit),进程直接从内存里读取这个数据。如果没有找到(cache miss),在进程访问这个数据之前它先将数据从数据块拷贝到缓存里。通过cache hit访问数据的速度要比cache miss访问数据的速度要快。

在读数据块到缓存之前,进程先要找到一个free buffer。进程在LRU list里找free buffer,从列表的least recently used的末尾开始找。进程直到找到free list为止或者找到buffer的阈值为止。

如果用户进程搜寻LRU list时找到了一个dirty buffer,它会将这个dirty buffer移动到write list然后继续寻找。当用户进程找到free buffer后,它把磁盘中的读数据块读到buffer里然后将buffer移动到LRU list中的MRU的尾部。

如果用户进程没有搜索到free list而是找到了buffer的阈值限制,进程会停止搜索,调用DBW0后台进程将一些dirty buffer写到磁盘里。

  • LRU算法和全表扫描

当后台进程执行全表扫描时,它将表的数据块读到buffer里,然后将它们放到LRU list中LRU的尾部(代替MRU的尾部),这是因为全表扫描只是偶尔需要,因此这些数据块会很快的被移除缓存而保留一些经常用到的数据块到缓存里。

你可以在表与表的基础上控制全表扫描时的默认动作。为了把包含表的数据块放到LRU表的MRU末尾,当创建或修改表的时候可以使用cache子句。为了避免访问表的子查询出现I/O问题,你可以考虑为小的表或大的静态的历史数据表采取这种动作。

  • 数据缓冲区的大小

在一个数据库中Oracle支持多种数据块大小。Oracle中标准数据块用于SYSTEM表空间。可以通过设置初始化参数DB_BLOCK_SIZE来指定标准数据块的大小。合法的值可以从2K到32K。

你也可以选择设置两个附加的缓存池的大小:KEEP和RECYCLE,可以通过参数DB_KEEP_CACHE和DB_RECYCLE_SIZE来设置。这三个参数是相互独立的。

通过下列参数来设置非标准数据块缓冲区的成员和大小:

DB_2K_CACHE_SIZE

DB_4K_CACHE_SIZE

DB_8K_CACHE_SIZE

DB_16K_CACHE_SIZE

DB_32K_CACHE_SIZE

设置Block和Cache大小的例子:

DB_BLOCK_SIZE=4096

DB_CACHE_SIZE=1024M

DB_2K_CACHE_SIZE=256M

DB_8K_CACHE_SIZE=512M

在上面的例子中,标准数据块大小为4K,标准数据库块的缓存是1024M,大小为2K的数据块的缓存是256M,而8K的为512M。

数据缓冲区有大小的限制,因此不是所有的数据块都能够写到数据缓冲区。因此当访问数据库出现cache miss时导致数据库将dirty data写到磁盘而空出空间供新的数据使用。

数据缓冲区的大小会影响cache hit的结果。增加缓存区得大小会增加cache hit的概率。

你可以在数据库实例运行时修改buffer cache的大小,而不需要停止数据库。通过ALTER SYSTEM命令可以达到目的。

通过V$BUFFER_POOL可以跟踪不同缓存部件的大小和正在重新分配大小的操作。

  • Multiple Buffer Pools

你可以用独立的buffer pools配置数据库缓冲区来保证或者将数据保存在缓存里或者当放在缓存中的数据快被使用后缓冲区马上就能被新的数据使用。特别的Schema对象(tables,clusters,indexes和partions)可以被指定到合适的buffer pool保证他们的数据库移出缓存的方式。

  • KEEP buffer pool将模式对象的数据块保留在内存中。
  • 只要数据块不需要使用时RECYCLE buffer pool就将它移出内存。
  • 当shema对象的数据块没有分配任何buffer pool时就自动的分配到DEFAULT buffer pool。

可以通过设置初始化参数DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE来设置KEEP和RECYCLE buffer pools的大小。

  • Redo Log Buffer

Redo log buffer是SGA中的一个循环的缓存,它保存的是对数据库的改变信息。这些信息保存在redo enties里。Redo entries包含重构,重做的必要信息,以及insert,update,delete,create,alter,drop等语句对数据库的改变。Redo entries在必要时用于数据库的恢复。

数据库进程将用户内存空间中的信息拷贝到SGA中Redo buffer的Redo entries。Redo buffer占据缓存中连续的区域。后台进程LGWR把Rebo log buffer中的数据写到磁盘活动的redo log file。

初始化参数LOG_BUFFER的值(以KB为单位)决定了redo log buffer的大小。通常来说,值越大越能减少log file的I/0操作,特别是事务很长或很多时。默认的值可以是512KB或CPU_COUNT参数的128KB倍。

  • Shared pool

SGA中的shared pool包含library cache,dictionary cache,用于存放并行运行信息的缓存,控制结构。

shared pool的大小由初始化参数shared_pool_size的值决定。这个参数在32位的平台中默认的值是8M,在64位平台中默认的值是64M。增加这个参数的值就等于增加了系统预留给shared pool的内存大小。

  • Library cache

Library cache包含shared SQL areas,private SQL areas(在共享服务器配置模式中),PL/SQL过程和包,锁和library cache句柄等控制信息。

Shared pool区能被所有用户访问,因此library cache在SGA的shared pool中。

  • Share SQL Areas和Private SQL Areas

Oracle在执行每个SQL时都有一个shared SQL area和一个private SQL area。当两个用户执行相同的SQL语句时,Oracle会为这两个用户重用shared SQL area。当然,每个用户需要有一个包含语句的私有SQL area的单独拷贝。

Shared SQL Areas:一个shared SQL area包含parse tree和给定SQL语句的执行计划。Oracle通过使用为多次执行的SQL语句划分专门的区域的方式来节省内存。

当一个新的SQL语句被解析时Oracle从Share pool中分配内存,然后保存到 shared SQL area。分配内存的大小取决于语句的复杂度。如果整个shared pool已经被分配出去,Oracle会使用修改过的LRU算法从pool中收回内存直到shared SQL area中足够的空闲内存分配跟新的语句时,如果Oracle收回了一块shared SQL area,与这块区域相连的SQL语句需要重新解析,并且在语句下次执行时需要重新指派另外一块shared SQL area。

  • PL/SQL Program Units and Shared Pool

Oracle处理PL/SQL程序单元(过程,函数,包,匿名块,触发器)的方式与处理单独SQL语句相同。Oracle分配一个shared area保存一个程序单元的分析,编译形式。Oracle分配一私有区域保存运行这个程序的会话的特有值,包括执行程序需要的本地的,全局的,和包变量和缓冲。如果不只是一个用户执行同样的程序单元,然后共同的shared area被所有用户共享,然而每个用户维护他们各自私有SQL area的单独拷贝来保证分配给他们的会话的值。

  • Dictionary Cache

数据字典是一组包含数据库数据库结构,数据库用户信息的数据表和视图的集合。当Oracle对SQL语句进行语法分析时会频繁的访问数据字典。这种访问是Oracle继续运行比不可少的部分。

因为数据字典被Oracle如此频繁的访问,因此在Oracle中有2块专门的区域来存放数据字典。第一个区域是data dictionary cache,也叫row cache应为它一行代理缓存来保存数据。另一个存放字典数据的区域是library cache。所有的用户进程共享这两个区域来存放数据字典的信息。

  • Allocation and Reuse of Memory in Shared Pool

在通常情况下,share pool中的任何一条信息直到使用改进的LRU算法刷新之前都会留着share pool中。没有被使用的条目的内存将会被释放来为新的条目分配内存。改进的LRU算法保证了只要条目有用他们将会被放在内存中,即使最初创建这个条目的进程已经终止。因此,处理关联多用户的Oracle系统的SQL语句的开销减小了。

当SQL语句提交到Oracle运行时,Oracle自动执行下面的内存分配步骤:

1.Oracle检查是否存在相同语句的,如果有,这个shared SQL area将会用于这个新来的语句执行。如果这个语句没有shared SQL area,oracle在shared pool中为它分配一个。另一方面,用户的私有SQL区域shared SQL area包含这个语句。

2.Oracle分配一个私有代表这个session。这个私有 SQL area的位置取决于session的建立连接的方式(专有模式或共享模式)。

Oracle会在下列情况下刷新share pool area:

  • 当ANALYZE语句用于更新或删除表,cluster,索引,的数据时,所有包含被分析对象的shared SQL area都会从shared pool刷新。下一次刷新语句运行,被解析的语句在一个新的共享SQL区引用对象的新数据。
  • 如果SQL语句引用的对象不论以任何方式被修改,share SQL area就变得无效(标识为无效),这个语句在下次执行时需要重新被分析。
  • 如果你修改了数据库的全局名字,shared pool的所有信息都会被更新。
  • 数据库管理员可以在实例运行的情况下,为了性能评估(针对shared pool,而不是data buffer cache)而手动的刷新shared pool里的所有信息,完成这个任务的语句是ALTER SYSTEM FLUSH SHARED POOL.