欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PGA管理

程序员文章站 2022-07-14 19:21:48
...

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

UGA堆中所包含的内存结构
私有SQL区域(Private SQL Area):这部分区域包含绑定变量信息以及运行时的内存结构等数据。每一个发出SQL语句的session都有自己的私有SQL区域。这部分区域又可分成以下两部分。
永久内存区域:这里存放了相同SQL语句多次执行时都需要的一些游标信息,比如绑定变量信息、数据类型转换信息等。这部分内存只有在游标被关闭时才会被释放。
运行时区域:在处理SQL语句时的第一步就是要创建运行时区域,这里存放了当SQL语句运行时所使用的一些信息。对于DML(INSERT、 UPDATE、DELETE)语句来说,SQL语句执行完毕就释放该区域;而对于查询语句(SELECT)来说,则是在所有数据行都被获取并传递给用户以后被释放,或者该查询被取消以后也会被释放。
Session相关的信息。这部分信息包括以下几部分。
正在使用的包(package)的状态信息。
使用alter session这样的命令所启用的跟踪信息,或者所修改的session级别的优化器参数(optimizer_mode)、排序参数(sort_area_size等)、修改的NLS参数等。
所打开的db links。
可使用的角色(roles)等。
工作区(Work area):这块区域主要用来存放执行SQL的过程中所产生的中间数据,比如排序时,需要在这里存放排序过程中的中间数据。这部分占据了PGA中的大部分空间。其大小依赖于所要处理的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中进行分配的。

PGA自动管理

在Oracle 9i之前,我们主要是通过设置sort_area_size、hash_area_size等参数值(通常都叫做*_area_size)来管理PGA的 使用,不过严格说来,是对PGA中的UGA进行管理。但是,这里有个问题,就是这些参数都是针对某个session而言的,也就是说设置的参数值对所有登 录到数据库的session都生效。在数据库实际运行过程中,总有些session需要的PGA多,而有些session需要的PGA少。如果都设置一个 很小的*_area_size,则会使得某些SQL语句运行时由于需要将临时数据交换到磁盘而导致效率低下。而如果都设置一个很大的值,又有可能一方面浪费空间;另一方面,消耗过多内存可能导致操作系统其他组件所需要的内存短缺,而引起数据库整体性能下降。所以如何设置*_area_size的值一直都是 DBA很头疼的一个问题。

而从Oracle 9i起(当然也包括Oracle 10g)所引入的一个新的特性可以有效的解决这个问题,这个特性就是自动PGA管理。

首先,设置workarea_size_policy参数。该参数为auto(也是默认值)时,表示启用PGA自动管理;而设置该参数为 manual时,则表示禁用PGA自动管理,仍然沿用Oracle 9i之前的方式,也就是使用*_area_size对PGA进行管理。
然 后,DBA可以根据数据库的负载情况估计所有session大概需要消耗的PGA的内存总和,然后把该值设置为初始化参数 pga_aggregate_target的值即可。Oracle会按照每个session的需要为其分配PGA,同时会尽量维持整个PGA的内存总和不 超过该参数所定义的值。这样的话,Oracle就能尽量避免整个PGA的内存容量异常增长而影响整个数据库的性能。从而,就有效的解决了设 置*_area_size所带来的问题。

不过遗憾的是,Oracle 9i下的PGA自动管理只对专用连接方式有效,对共享连接方式无效。Oracle 10g以后对两种连接方式都有效。

在PGA中,对性能影响最大的就是SQL工作区了。通常来说,SQL工作区越大则对于SQL语句的执行的效率就高,从而对于用户的响应时间就越少。 理想情况下,SQL工作区应该可以容纳SQL执行过程中所涉及的所有输入数据和控制信息。当然,这只是理想情况,现实往往总是不能尽如人意,很多情况下 SQL工作区是不能容纳执行SQL所需要的内存空间的,从而不得不交换到临时表空间里。为了衡量执行SQL所需要的内存与实际分配给该SQL的SQL工作 区之间的契合程度,Oracle将所分配的SQL工作区大小分成以下三种类型。
optimal尺寸:SQL语句能够完全在所分配的SQL工作区内完成所有的操作。这时的性能最佳。

onepass尺寸:SQL语句需要与磁盘上的临时表空间交互一次才能够在所分配的SQL工作区中完成所有的操作。

multipass尺寸:由于SQL工作区过小,从而导致SQL语句需要与磁盘上的临时表空间交互多次才能完成所有的操作。这个时候的性能将急剧下降。

当系统整体负载不大时,Oracle倾向于为每个session的PGA分配optimal尺寸大小的SQL工作区。

而随着负载上升,比如连接的session逐渐增多导致同时执行的SQL语句越来越多时,Oracle就会倾向于为每个session的PGA分配onepass尺寸大小的SQL工作区,甚至是multipass尺寸的SQL工作区了。

我们一旦设置了pga_aggregate_target以后,所有的*_area_size就将被忽略。那么,我们该如何来设置该参数的值呢?这依赖于数据库的用途,如果数据库为OLTP(联机事务处理)应用的,则其应用一般都是小的短的进程,所需要的PGA也相应较少,所以该值该值通常为总共分配给Oracle实例的20%,另外的80%则给了SGA;如果数据库为OLAP(DSS)(数据仓库或决策分析)应用的,则其应用一般都是很大的,运行时间很长的进程,因此需要的PGA就多。所以通常为PGA分配50%的内存。而如果数据库为混合类型的,则情况比较复杂,一般会先分配40%的初始值,而 后随着数据库的应用,而不断对PGA进行监控,并进行相应的调整。

比如,对于8GB物理内存的数据库服务器来说,按照Oracle推荐的,分配给Oracle实例的内存为物理内存的80%。那么对于OLTP应用来 说,pga_aggregate_target的值大约就是1310MB((8192MB×80%)×20%)。而对于OLAP来说,则该值大约就是 3276MB((8192MB×80%)×50%)。

当然,这里所说的都是对于一个新的数据库来说,初始设置的值。这些值并不一定正确,可能设置过大,也可能设置过小。必须随着系统的不断运行,DBA需要不断监控,从而对其进行调整。

Oracle为了帮助我们确定这个参数的值,引入了一个新的视图v$pga_target_advice。为了使用该视图,需要将初始化参数statistics_level设置为typical(默认值)或all。

SQL> select
2     round(pga_target_for_estimate /(1024*1024)) "Target (M)",
3     estd_pga_cache_hit_percentage "Est. Cache Hit %",
4     round(estd_extra_bytes_rw/(1024*1024)) "Est. ReadWrite (M)",
5     estd_overalloc_count "Est. Over-Alloc"
6    from v$pga_target_advice
7  /



Target (M)        Est. Cache Hit %    Est. ReadWrite (M)   Est. Over-Alloc
------------------------------------------------------------------------
15      34                      264                 1
30      34                      264                 0
45      34                      264                 0
60      67                       66                 0
72      67                       66                 0
84      67                       66                 0
96      67                       66                 0
108     67                       66                 0
120     67                       66                 0
……
360     67                       66                 0
480     67                       66                 0

该输出告诉我们,按照系统目前的运转情况,我们PGA设置的不同值所带来的不同效果。根据该输出,随着我们增加PGA的尺寸,estd_pga_cache_hit_percentage不断增加,同时estd_extra_bytes_rw(表示onepass、 multipass读写的字节数)不断减小。从上面的结果我们可以知道,将pga_aggregate_target设置为60MB是最合理的,因为即便将其设置为480MB,命中率也不会有所提高。

注意:即使设置了PGA_AGGREGATE_TARGET以后,每个进程PGA内存的大小也是受限制的:
串行操作时,每个进程可用的PGA内存为MIN(PGA_AGGREGATE_TARGET * 5%, _pga_max_size/2),其中隐含参数_pga_max_size的默认值是200M,不建议修改它。
并行操作时,并行语句可用的PGA内存为PGA_AGGREGATE_TARGET * 30% / DOP (Degree Of Parallelism 并行度)。


参考至:《教你成为10g OCP》韩思捷著

如有错误,欢迎指正

邮箱:czmcj@163.com