作者:沃趣科技高级数据库工程师  魏兴华 




概述

大家好,我是魏兴华,你们可以叫我肉丝,我的英文名是Rose魏。在这篇文章中,我给大家介绍一些Oracle内存管理和大页的知识。Oracle发展这么多年,提供了多种的内存管理方式,从最早SGAPGA手工管理,到9I版本出现的PGA的自动管理,到10G版本出现的SGA自动管理(ASMM),再到11G版本出现的memory自动管理(AMM)Oracle基本是在朝着智能化、傻瓜化、自动化的方向稳步前进着,对于初学OracleDBA来说,看到这些不同的内存管理方式一定心里有着不同程度的疑惑,例如:

·          Oracle有这么多内存分配的管理方式,我该使用哪一种?是使用11G版本推出的AMM管理方式,还是使用10G版本出现的ASMM管理方式?或者干脆使用最旧的手工方式管理内存?


·         我该为我的实例SGAPGA分别设置多大呢?

·         我该为buffer cacheshared pool分配多大的内存空间?

·         什么情况下我该使用大页?为什么大页这个词最近几年这么容易听到?
·         有没有一些简单粗暴的算法来搞定这一切?

写这篇文章的初衷也来源于上面这些非常正常的疑问,如果这篇文章能给有这些疑惑的DBA朋友一些指导和帮助,那肉丝我也就真的功莫大焉了。


Memory
构成

在一个运行着Oracle数据库的专用服务器上,内存基本上被以下内容所占用:
·               Kernel
·               OS Page Table
·               文件系统Cache
·               SGA
·               PGA
·               Oracle进程
·              其他进程(RMAN,非Oracle的进程等等)



严格来说OS Page Table也算是Kernel Memory部分的内容,由于本文后面会重点讲大页的内容,因此把OS Page Table这部分在图中独立了出来,以引起读者注意。必须要强调,Oracle不应该使用掉主机上的所有内存,过量的内存分配会诱发操作系统SWAP的产生,导致Oracle性能严重降低,在RAC环境下,内存不足还非常容易导致RAC节点的驱逐。对于Oracle两大块内存:SGAPGADBA一定要仔细根据系统特点、业务使用特点做好规划和设计,以防出现OS内存不够用的情况。

内存自动化发展历程

我们首先了解一下Oracle内存发展的历程,基本上Oracle的内存管理在版本的演进过程中沿着越来越智能化、自动化、傻瓜化的方向前进。接触过MYSQL等数据库的DBA朋友应该比较清楚,这些数据库基本上都还需要DBA去决定每个内存组件的大小,而Oracle已经从9I版本开始就迈向智能化、自动化的过程了。下图是Oracle内存管理的一个演进图:

PGA 自动管理

Oracle是多进程的架构,这点区别于MYSQLMYSQL是单进程多线程的架构,Oracle会为每一个用户连接创建一个独立的操作系统进程来为用户提供服务,这个进程叫做服务器进程或者影子进程,它像是用户的一个代理,来操作数据文件或者SGA内存,由于服务器进程的代码是Oracle公司开发的,所以Oracle公司完全相信这些进程或代码是安全的,因此这些进程可以直接操作数据文件和SGA内存,这些进程接受用户进程发送的指令,并完成相关的操作,并根据需要来给用户进程返回结果。由于服务器进程是操作系统上的一个进程,因此它本身需要占用一些操作系统内存,除此之外,进程在对数据进行读取、排序、hash过程中,也会占用一定量的内存,在Oracle 9I版本之前,对于服务器进程的内存管理是由一些参数去控制的,以下参数代表每一个服务器进程可以使用的不同区域的内存大小(都是进程的私有内存区域):
·         SORT_AREA_SIZE
·         HASH_AREA_SIZE
·         BITMAP_MERGE_AREA_SIZE
·         CREATE_BITMAP_AREA_SIZE
例如,SORT_AREA_SIZE控制了每一个进程可用的排序区大小,HASH_AREA_SIZE参数控制了每一个进程可用的hash区大小,这些参数都有默认值,但是默认值是否合适,需要打上一个大大的问号,因为不同的任务对于PGA内存的不同区域有不同的要求,例如,如果是做排序操作,就对排序区内存要求较大,而对hash区没任何的要求。当然如果默认值不合适,DBA可以手工调整这些区域的大小。

Oracle 9I版本出现了PGA的自动管理,不再需要像9I之前版本需要设置一系列参数来控制PGA的使用,只需要设置PGA_AGGREGATE_TARGET为一个值,就可以控制所有的服务器进程的PGA使用量,至于每个服务器进程使用了多少排序区,hash区,都交给Oracle去控制。


一般情况下对于PGA的大量使用有如下几种操作:
·         hash 对于hash join操作,hash桶所占用的内存就在进程的私有PGA内存中,而不是在共享内存SGA中,如果使用PGA手工管理的话,可以通过HASH_AREA_SIZE参数来动态调整会话进行hash操作能够使用的内存量。
·          sort 对于排序操作,例如查询语句里的order by、创建索引的排序操作等占用的内存也在PGA中,如果使用PGA手工管理,可以通过SORT_AREA_SIZE参数动态调整会话排序操作可以使用的内存量。
·         parallel 并行操作简直可以说是PGA内存的杀手,每一个并行进程都能使用到最多2GPGA内存,当然Oracle会确保所有的并行slave使用的PGA内存不能超过PGA_AGGREGATE_TARGET的一半。

现在Oracle的版本已经出到了12CPGA的自动管理已经发展了很多个年头,如果是个人,也应该是一个非常成熟的小伙子了,甚至是位大叔了????,绝大部分数据库操作完全没必要再去手工调整PGA的一些参数。不过,我们依然能从互联网上、论坛上看到有很多DBA对这种手工调整PGA的技术崇拜有加(我以前也是),确实在一些情况下,通过手工调整PGA的相关内存区,可以达到加速排序等一些操作的目的,但是如果需要操作的数据量非常的大,那这种调整往往是费时费力,甚至是徒劳的,因为对于一个进程的私有PGA内存来说,像sort,hashP区域的内存分配是有限制的,现在11GR2的版本对于每个进程的PGA内存最大限制默认是2G,且排序区可以使用的只有1G,如果你的排序等操作需要的内存远远不止12G,那么这种优化就非常的徒劳,甚至还可能变慢(肉丝亲身遭遇过变慢的案例????)。是否使用PGA自动管理由参数WORKAREA_SIZE_POLICY控制,它的值可以为automanual,顾名思义,autoPGA自动管理,manualPGA手工管理,回到9I之前的使用方式。


这里肉丝提供几个大家可能会感兴趣的隐含参数,比如我上面提到了每个进程最大能使用的PGA不能超过2G,通过修改隐含参数可以突破这个限制。 >肉丝在这里警戒各位,这些参数如果要在生产环境使用,请在你的数据库版本下做好测试。
以下为11GR2版本的情况,其他版本并未做测试:
·         _PGA_MAX_SIZE 每个进程的PGA的最大内存大小。默认值为:21474836482G,单位为B
·         _SMM_MAX_SIZE 每个进程的工作区的大小,默认值为1/2 _PGA_MAX_SIZE1048576 ,单位KB1GB,排序区、hash区都属于工作区的范围。64位系统下真实使用的排序区内存不能超过4GB
·         _SMM_PX_MAX_SIZE 所有并行查询的SLAVE进程能够用到的PGA总量。默认值为 1/2 pga_aggregate_target,单位为KBRAC环境下,每个节点都可以用到这么多内存。

以上全部为动态参数,可以在session/system级别来在线修改。
alter system set"_SMM_PX_MAX_SIZE"=10485760; 
alter system set"_SMM_MAX_SIZE"=1048576;
alter system set"_PGA_MAX_SIZE"=2147483648;

上面的参数调整后,一定要设置对应的pga_aggregate_target,否则以上调整可能会不起作用,建议设置为修改后的_SMM_PX_MAX_SIZE的值的两倍。

默认情况下,每个进程使用的排序区不能超过1G。由参数_SMM_MAX_SIZE(单位KB)控制,默认为_PGA_MAX_SIZE(单位B)的一半。 例如,并行度20创建索引,总共可以使用的排序区大小为20*1G=20G,但是同时还受参数_SMM_PX_MAX_SIZE的控制,所有的slave占用的内存不能超过_SMM_PX_MAX_SIZE的值(单位为KB),默认为pga_aggregate_target的一半。同时64位系统下,每个进程可以使用的排序空间不能超过4G。所以即使把_SMM_MAX_SIZE调整大于4G也没有用。_SMM_PX_MAX_SIZE,所有并行查询的SLAVE进程能够用到的PGA总量。每个RAC 节点都可以用到这么多,限制的是本节点所有并行slave能够消耗的PGA

如何为
PGA_AGGREGATE_TARGET
设置一个合理的值?

PGA_AGGREGATE_TARGET的设定经常是一个摸索的过程,这里给出官方的一个分配指导原则


PGA_AGGREGATE_TARGET =(TOTAL_MEM * 80%) * 20% for an OLTP system

PGA_AGGREGATE_TARGET = (TOTAL_MEM * 80%) * 50%for a DSS system

上面公式中的TOTAL_MEM * 80%代表着Oracle可以使用的所有内存为操作系统的80%,再根据不同类型业务的特点,OLTP系统,可以在此基础上分配20%的内存给PGADSS分析型系统,可以给出剩余内存的50%。这个只是一个指导的意见,具体情况要具体分析。例如,你的OLTP系统上有成千上万个连接,那么你可以粗略的按照每个进程占用10M的内存来大体的计算一下PGA需要占用的内存空间,再者,假如你的系统不但连接数非常多,而且活跃的连接数也非常的多,那么你可以按照每个进程至少12M的内存来进行估算,更为重要的,系统中假如存在非常多的临时性的计算任务,那么要为PGA预留的内存就更多了。 例如,并行度设置为5创建索引,每个并行进程占用的PGA内存接近1G


select *  from 
(select PGA_USED_MEM/1024/1024,PGA_ALLOC_MEM/1024/1024,PGA_MAX_MEM/1024/1024

from v$process order by 1 desc) whererownum<14;

PGA_USED_MEM/1024/1024  PGA_ALLOC_MEM/1024/1024  PGA_MAX_MEM/1024/1024

---------------------- --------------------------------------------
    
1043.70779          1044.39673        1044.39673
904.724821          905.334227        905.334227
851.350813          851.959227        851.959227
804.526175          805.146727        805.146727
589.