技术开发 频道

PGA自动管理原理深入分析及性能调整

[IT168技术文档]

1. PGA的概念以及所包含的内存结构
作为一个复杂的oracle数据库系统来说,每时每刻都要处理不同的用户所提交的SQL语句,获取数
据并返回数据给用户。众所周知,解析SQL语句的工作是在oracle实例中的shared pool所完成的。那么对于每个session来说,其执行SQL语句时所传入的绑定变量放在哪里?而且,对于那些需要执行比较复杂SQL的session来说,比如需要进行排序(sort)或hash连接(hash-join)时,这时这些session所需要的内存空间又从哪里来?另外,还有与每个session相关的一些管理控制信息又放在哪里?对于诸如此类与每个session相关的一些内存的分配问题,oracle通过引入PGA这个内存组件来进行解决。

1.1 PGA的相关概念
 PGA按照oracle官方文档解释,叫做程序全局区(Program Global Area),但也有些资料上说还可以理解为进程全局区(Process Global Area)。这两者没有本质的区别,它首先是一个内存区域,其次,该区域中包含了与某个特定服务器进程相关的数据和控制信息。每个进程都具有自己私有的PGA区,这也就意味着,这块区域只能被其所属的进程进入,而不能被其他进程访问,所以在PGA中不需要latch这样的内存结构来保护其中的信息。笼统的来说,PGA里包含了当前进程所使用的有关操作系统资源的信息(比如打开的文件句柄等)以及一些与当前进程相关的一些私有的状态信息。
 每个PGA区都包含两部分:
固定PGA部分(Fixed PGA):这部分包含一些小的固定尺寸的变量,以及指向变化PGA部分的指针。
变化PGA部分(Variable PGA):这部分是按照堆(Heap)来进行组织的,所以这部分也叫做PGA堆。可以从X$KSMPP视图中看到有关PGA堆的分布信息。PGA堆中所包含的内存结构包括:
 有关一些固定表的永久性内存。
如果session使用的是专用连接方式(dedicated server),则还含有用户全局区(UGA-User Global Area)子堆。如果session使用的是共享连接方式(shared server),则UGA位于SGA中。
调用全局区(CGA-Call Global Area)子堆。

1.2 UGA(用户全局区)的相关概念
 UGA是包含与某个特定session相关信息的内存区域,比如session的登录信息以及session私有的SQL区域等。每个UGA也包含两个部分:
 固定UGA部分(Fixed UGA):这部分包含一些小的固定尺寸的变量,以及指向变化UGA部分的指针。
 变化UGA部分(Variable UGA):这部分也是按照堆来进行组织的,可以从X$KSMUP视图中看到有关UGA堆的分布情况。UGA堆的分布与OPEN_CURSORS、OPEN_LINKS等参数有关系。所谓的游标(cursor)就是放在这里的。UGA堆中所包含的内存结构包括:
 私有SQL区域(Private SQL Area):这部分区域包含绑定变量信息以及运行时的内存结构等数据。每一个发出SQL语句的session都有自己的私有SQL区域。这部分区域又可分成两部分:
  永久内存区域:这里存放了相同SQL语句多次执行时都需要的一些游标信息,比如绑定变量信息、数据类型转换信息等。这部分内存只有在游标被关闭时才会被释放。
 运行时区域:这里存放了当SQL语句运行时所使用的一些信息。这部分区域的大小尺寸依赖于所要执行的SQL语句的类型(sort或hash-join等)和复杂度以及所要处理的数据行的行数以及行的大小。在处理SQL语句时的第一步就是要创建运行时区域,对于DML(INSERT、UPDATE、DELETE)语句来说,SQL语句执行完毕就释放该区域;而对于查询语句(SELECT)来说,则是在所有数据行都被获取并传递给用户以后被释放,或者该查询被取消以后也会被释放。
 Session相关的信息。这部分信息包括:
正在使用的包(package)的状态信息。
使用alter session这样的命令所启用的跟踪信息、或者所修改的session级别的优化器参数(optimizer_mode)、排序参数(sort_area_size等)、修改的NLS参数等。
 所打开的dblinks。
 可使用的角色(roles)等。
从上面可以很明显的看出,我们最需要关注的就是私有SQL区域中的运行时区域了。实际上,从9i
以后,对这部分区域有了一个新的名称:SQL工作区域(SQL Work Area)。SQL工作区域的大小依赖于所要处理的SQL语句的复杂程度而定。如果SQL语句包含诸如group by、Hash-join等这样的操作,则会需要很大的SQL工作区域。实际上,我们调整PGA也就是调整这块区域。后面还会说到这部分内容。
 而UGA所处的位置完全由session连接的方式决定:
 如果session是通过共享服务器(shared server)方式连到数据库的,则毫无疑问,UGA必须能够被所有进程访问,所以这个时候UGA是从SGA中进行分配的。进一步说,如果SGA中设置了large pool,则UGA从large pool里进行分配;否则,如果没有设置large pool,则UGA只能从shared pool里进行分配了。
如果session是通过专用服务器(dedicated server)方式连到数据库的,则UGA是从进程的PGA中进行分配的。

1.3 CGA(调用全局区)的相关概念
 CGA也是一块内存区域,但它是动态的,随着调用(call)的开始而创建,在调用过程中一直存在,直到调用结束时被释放。它存放的是在调用过程中所需要的数据。
我们知道,调用主要包括解析(parse)调用、执行(executive)调用、获取(fetch)调用以及递归SQL调用和PL/SQL调用。从调用的种类可以看出,实际上在调用过程中所需要的数据,比如SQL AREA,PL/SQL AREA和SORT AREA基本都是放在UGA中的,因为这些数据在各个调用之间必须一直存在并可用。而在CGA中只存放了在调用过程中临时需要的数据,比如直接I/O缓存(Direct I/O Buffer)以及堆栈空间等数据结构。因此,没有CGA中的数据结构,调用是无法完成的。
注意,CGA不象UGA可以位于SGA中(以共享服务器模式连接),CGA一定是位于PGA中的。如果当前进程正在运行,则每个PGA中只有一个CGA。如果当前进程没有运行,则该进程的PGA中就没有CGA。

1.4 转储PGA
就象实例中的其他内存结构一样,oracle同样提供了可以将PGA转储到跟踪文件的方法。方法如下:
SQL> alter session set events 'immediate trace name heapdump level n';
其中的level n决定了将哪些内存堆转储到跟踪文件:
Level 1:  PGA汇总信息
Level 2:  SGA汇总信息
Level 4:  UGA汇总信息
Level 8:  当前调用的汇总信息(CGA)
Level 16:  用户调用的汇总信息(CGA)
Level 32:  Large pool的汇总信息(LGA)
Level 1025:  PGA详细信息
Level 2050:  SGA详细信息
Level 5000:  UGA 详细信息
Level 8200:  当前调用的详细信息
Level 16400:  用户调用的详细信息
Level 32800:  Large pool的详细信息

举例来说,我们转储PGA的汇总信息:
SQL> alter session set events 'immediate trace name heapdump level 1';
  到user_dump_dest所定义的目录下,找到跟踪文件并打开,可以看到类似下面的信息:
******************************************************
HEAP DUMP heap name="pga heap"  desc=001DB880
 extent sz=0x213c alt=84 het=32767 rec=0 flg=2 opc=2
 parent=00000000 owner=00000000 nex=00000000 xsz=0x213c
EXTENT 0 addr=03700034
  Chunk  370003c sz=     8500    perm      "perm           "  alo=7524
EXTENT 1 addr=0351BC8C
  Chunk  351bc94 sz=     9156    freeable  "Fixed Uga      "
EXTENT 2 addr=03519B3C
  Chunk  3519b44 sz=     3764    perm      "perm           "  alo=3764
  Chunk  351a9f8 sz=     4196    free      "               "
  Chunk  351ba5c sz=      540    freeable  "kopolal dvoid  "
……………
  Chunk  45e988c sz=     4144    recreate  "Alloc environm "  latch=00000000
     ds  45eade0 sz=     4144 ct=        1
  Chunk  45ea8bc sz=     1484    freeable  "kpuinit env han"
  
我们可以看到,其中的红色部分就是在PGA中所包含的固定UGA部分。同时,我们可以使用如下的命令将PGA的子堆也给转储出来,其中9.2以前使用:
SQL> alter session set events 'immediate trace name heapdump_addr level n';
9.2以后使用:
SQL> alter session set events 'immediate trace name heapdump_addr level 1, addr n';
其中的n表示子堆的地址。而子堆的地址可以在PGA的转储文件中找到。比如上面的例子中,我们可以看到这样的一行:
     ds  45eade0 sz=     4144 ct=        1
这里的ds 45eade0就是某个子堆的地址,这是个十六进制的数值,于是我们先将其转换为十进制数值:
SQL> select to_number('45eade0','xxxxxxxx') from dual;
TO_NUMBER('45EADE0','XXXXXXXX')
-------------------------------
                       73313760
这里的73313760就是转储PGA子堆的命令中的n,所以我们可以执行(我的测试库为9.2.0.5):
SQL> ALTER SESSION SET EVENTS 'immediate trace name heapdump_addr level 1, addr 73313760';

0
相关文章