Oracle PGA详解

转自:http://yanguz123.iteye.com/blog/1542369

  PGA(Program Global Area 程序全局区)是一块包含一个服务进程的数据和控制信息的内存区域。它是 Oracle 在一个服务进程启动是创建的,是非共享的。一个 Oracle 进程拥有一个 PGA 内存区。一个 PGA 也只能被拥有它的那个服务进程所访问,只有这个进程中的 Oracle 代码才能读写它。因此, PGA 中的结构是不需要 Latch 保护的。
  我们可以设置所有服务进程的 PGA 内存总数受到实例分配的总体 PGA ( Aggregated PGA )限制。
  在专有服务器( Dedicated Server )模式下, Oracle 会为每个会话启动一个 Oracle 进程;而在多线程服务( Multi-Thread Server MTS )模式下,由多个会话共享通一个 Oracle 服务进程。
  PGA 中包含了关于进程使用到的操作系统资源的信息,以及一些关于进程状态的信息。而关于进程使用的 Oracle 共享资源的信息则是在 SGA 中。这样做可以使在进程以外中止时,能够及时释放和清除这些资源。

?Stack Space 是用来存储用户会话变量和数组的存储区域;   
?User Session Data 是为用户会话使用的附加存储区。     
|--Session Information   
|--Sort Area   
|--Cursor Information    
  注意 Session information (用户会话信息)在独占服务器中与在共享服务器中所处的内存区域是不同的。

1.PGA 的组成
   PGA 由两组区域组成:固定 PGA 和可变 PGA (或者叫 PGA 堆, PGA Heap 【堆—— Heap 就是一个受管理的内存区】)。固定 PGA 和固定 SGA 类似,它的大小时固定的,包含了大量原子变量、小的数据结构和指向可变 PGA 的指针。
  可变 PGA 是一个内存堆。它的内存段可以通过视图 X$KSMPP (另外一个视图 X$KSMSP 可以查到可变 SGA 的内存段信息,他们的结构相同)查到。 PGA 堆包含用于存放 X$ 表的的内存(依赖与参数设置,包括 DB_FILES 、 CONTROL_FILES )。

  总的来说, PGA 的可变区中主要分为以下三部分内容:
  1)私有 SQL 区;
  2)游标和 SQL 区
  3)会话内存

1.1 私有 SQL 区( Private SQL Area )
   私有 SQL 区包含了绑定变量值和运行时期内存结构信息等数据。每一个运行 SQL 语句的会话都有一个块私有 SQL 区。所有提交了相同 SQL 语句的用户都有各自的私有 SQL 区,并且他们共享一个共享 SQL 区。因此,一个共享 SQL 区可能和多个私有共享区相关联。

  一个游标的私有 SQL 区又分为两个生命周期不同的区:
  永久区:包含绑定变量信息。当游标关闭时被释放。
  运行区:当执行结束时释放。
  创建运行区是一次执行请求的第一步。对于 INSERT 、 UPDATE 和 DELETE 语句, Oracle 在语句运行结束时释放运行区。对于查询操作, Oracle 只有在所有记录被 fetch 到或者查询被取消时释放运行区。

1.2   游标和 SQL 区( Cursors and SQL Areas )
  一个 Oracle 预编译程序或 OCI 程序的应用开发人员能够很明确的打开一个游标,或者控制一块特定的私有 SQL 区,将他们作为程序运行的命名资源。另外, oracle 隐含的为一些 SQL 语句产生的递归调用(前面有介绍,读取数据字典信息)也使用共享 SQL 区。
  私有 SQL 区是由用户进程管理的。如何分配和释放私有 SQL 区极大的依赖与你所使用的应用工具。而用户进程可以分配的私有 SQL 区的数量是由参数 OPEN_CURSORS 控制的,它的默认值是 50 。
  在游标关闭前或者语句句柄被释放前,私有 SQL 区将一直存在(但其中的运行区是在语句执行结束时被释放,只有永久区一直存在)下去。应用开发人员可以通过将所有打开的不再使用的游标都关闭来释放永久区,以减少用户程序所占用的内存。

1.3 会话内存( Session Memory )
  会话内存是一段用于保存会话变量(如登录信息)和其他预会话相关信息的内存。对于共享服务器模式下,会话内存是共享的,而不是私有的。
  对于复杂的查询(如决策支持系统中的查询),运行区的很大一部分被那些内存需求很大的操作分配给 SQL 工作区( SQL Work Area )。这些操作包括:
  基于排序的操作( ORDER BY 、 GROUP BY 、 ROLLUP 、窗口函数);
  Hash Join
  Bitmap merge
  Bitmap create

  例如,一个排序操作使用工作区(这时也可叫排序区 Sort Area )来将一部分数据行在内存排序;而一个 Hash Join 操作则使用工作区(这时也可以叫做 Hash 区 Hash Area )来建立 Hash 表。如果这两种操作所处理的数据量比工作区大,那就会将输入的数据分成一些更小的数据片,使一些数据片能够在内存中处理,而其他的就在临时表空间的磁盘上稍后处理。尽管工作区太小时, Bitmap 操作不会将数据放到磁盘上处理,但是他们的复杂性是和工作区大小成反比的。因此,总的来说,工作区越大,这些操作就运行越快。
  工作区的大小是可以调整的。一般来说,大的工作区能让一些特定的操作性能更佳,但也会消耗更多的内存。工作区的大小足够适应输入的数据和相关的 SQL 操作所需的辅助的内存就是最优的。如果不满足,因为需要将一部分数据放到临时表空间磁盘上处理,操作的响应时间会增长。


2  PGA 内存自动管理
   SQL 工作区可以是自动的、全局的管理。 DBA 只要设置参数 PGA_AGGREGATE_TARGET 给一个实例的 PGA 内存指定总的大小。设置这个参数后, Oracle 将它作为一个总的全局限制值,尽量使所有 Oracle 服务进程的 PGA 内存总数不超过这个值。
  在这个参数出现之前, DBA 要调整参数 SORT_AREA_SIZE 、 HASH_AREA_SIZE 、 BITMAP_MERGE_AREA_SIZE 和 CREATE_BITMAP_AREA_SIZE (关于这些参数,我们会在后面介绍),使性能和 PGA 内存消耗最佳。对这些参数的调整是非常麻烦的,因为即要考虑所有相关的操作,使工作区适合它们输入数据大小,又要使 PGA 内存不消耗过大导致系统整体性能下降。
  9i 以后,通过设置了参数 PGA_AGGREGATE_TARGET ,使所有会话的工作区的大小都是自动分配。同时,所有 *_AREA_SIZE 参数都会失效。在任何时候,实例中可用于工作区的 PGA 内存总数都是基于参数 PGA_AGGREGATE_TARGET 的。工作区内存总数等于参数 PGA_AGGREGATE_TARGET 的值减去系统其他组件(如分配给会话的 PGA 内存)的内存消耗。分配给 Oracle 进程的 PGA 内存大小是根据它们对内存的需求情况来的。
  参数 WORKAREA_SIZE_POLICY 决定是否使用 PGA_AGGREGATE_TARGET 来管理 PGA 内存。它有两个值: AUTO 和 MANUAL 。默认是 AUTO ,即使用PGA_AGGREGATE_TARGET 来管理 PGA 内存。其实,从参数 WORKAREA_SIZE_POLICY 的名字上可以看出, Oracle 的 PGA 内存自动管理只会调整工作区部分,而非工作区部分(固定 PGA 区)则不会受影响。
  还有注意一点就是: 10g 之前, PGA_AGGREGATE_TARGET 只在专用服务模式下生效。而 10g 以后, PGA 内存自动管理在专有服务模式( Dedicated Server )和 MTS 下都有效。另外, 9i 在 OpenVMS 系统上还不支持 PGA 内存自动管理,但 10g 支持。
  设置了 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 并行度)。

  当用户进程连接到数据库并创建一个对应的会话时, Oracle 服务进程会为这个用户专门设置一个 PGA 区,用来存储这个用户会话的相关内容。当这个用户会话终止时,数据库系统会自动释放这个 PAG 区所占用的内存。这个 PGA 区对于数据库的性能有比较大的影响,特别是对于排序操作的性能。所以,在必要的时候合理管理 PGA 区,能够在很大程度上提高数据库的性能。

一、 PGA 与 SGA 的区别

  PGA( 程序缓存区 ) 与 SGA ( 系统全局区 ) 类似,都是 Oracle 数据库系统为会话在服务器内存中分配的区域。不过两者的作用不同,共享程度也不同。 SGA 系统全局区顾名思义,是对系统内的所有进程都是共享的。当多个用户同时连接到一个例程时,所有的用户进程、服务进程都可以共享使用这个 SGA 区。为此这个 SGA 的主要用途就是为不同用户之间的进程与服务进程提供一个交流的平台。除了这个作用,另外有一个重要的作用就是各种数据库的操作主要就是在这个 SGA 区内完成。

  而 PGA 程序缓冲区则主要是为了某个用户进程所服务的。这个内存区不是共享的,只有这个用户的服务进程本身才能够访问它自己的 PGA 区。做个形象的比喻, SGA 就好像是操作系统上的一个共享文件夹,不同用户可以以此为平台进行数据方面的交流。而 PGA 就好像是操作系统上的一个私有文件夹,只有这个文件夹的所有者才能够进行访问,其他用户都不能够访问。虽然程序缓存区不像其他用户的进程开放,但是这个内存区仍然肩负着一些重要的使命,如数据排序、权限控制等等都离不开这个内存区。

二、 为排序设置合理的排序区大小

  当用户需要对某些数据进行排序时,数据库是如何处理的呢 ? 首先,数据库系统会将需要排序的数据保存到 PGA 程序缓存区中的一个排序区内。然后再在这个排序区内对这些数据进行排序。如需要排序的数据有 2M ,那么排序区内必须至少要有 2M 的空间来容纳这些数据。然后排序过程中又需要有 2M 的空间来保存排序后的数据。由于系统从内存中读取数据比从硬盘中读取数据的速度要快几千倍,为此如果这个数据排序与读取的操作都能够在内存中完成,无疑可以在很大程度上提高数据库排序与访问的性能。如果这个排序的操作都能够在内存中完成,显然这是很理想的。但是如果 PGA 区中的排序区容量不够,不能够容纳排序后的数据,那会如何呢 ? 此时,系统会从硬盘中获取一个空间,用来保存这需要排序的数据。此时排序的效率就会降低许多。为此在数据库管理中,如果发现用户的很多操作都需要用到排序,那么会用户设置比较大的排序区,可以提高用户访问数据的效率。

  在 Oracle 数据库中,这个排序区主要用来存放排序操作产生的临时数据。一般来说,这个排序区的大小占据这 PGA 程序缓存取的大部分空间,这是影响 PGA 区大小的主要因素。在小型应用中,数据库管理员可以直接采用其默认的值。但是在一些大型的应用中,或者需要进行大量记录排序操作的数据库系统中,管理员可能需要手工调整这个排序区的大小,以提高排序的性能。如果系统管理员需要调整这个排序区大小的话,需要通过初始化参数 SORT_AREA_SIZE 来实现。为了提高数据访问与排序的性能,数据库系统利用内存比硬盘要快几千倍的实施,会将准备排序的数据临时存放到这个排序区,并在排序区内完成数据的排序。管理员需要牢记这个原则,并在适当的情况下调整排序区的大小,以提高数据访问与数据排序的性能。

三、 会话区保存着用户的权限等重要信息

  在程序缓存区内还包含着一个会话区。虽然绝大部分情况下,管理员不要维护这个会话区,可以让数据库系统进行维护。但是,管理员还是需要了解一下这个会话区的作用。因为这个会话区直接关系着数据库系统中数据的安全性。数据库系统不仅是存放数据的一个很好的载体,而且在还提供了一个统一管理数据的平台,可以根据实际需要,为不同的用户设置不同的访问权限。简单的说,在数据库中可以控制用户可以访问哪些数据。从而提高数据的安全性。

  当用户进程与数据库建立会话时,系统会将这个用户的相关权限查询出来,然后保存在这个会话区内。如此的话,用户进程在访问数据时,系统就会核对会话区内的用户权限信息,看看其是否具有相关的访问权限。由于系统将这个用户的权限信息存放在内存上,所以其核对用户权限的速度非常的快。因为系统不用再去硬盘中读取数据,直接从内存中读取。而从内存读取数据的效率要比硬盘上快几千倍。

  通常情况下,这个会话区内保存了会话所具有的权限、角色、性能统计等信息。这个会话区一般都是由数据库进行自我维护的,系统管理员不用干预。


四、 堆栈区保存变量信息

  有时候为了提高 SQL 语句的重用性,会在语句中使用绑定变量。简单的说,就是 SQL 语句可以接受用户传入的变量。从而用户只需要输入不同的变量值,就可以满足不同的查询需求。如现在用户需要查询所有员工的信息。然后其又要查询所有工龄在 3 年以上的员工等等。此时其实他们采用的是同一个 SQL 语句,只是传递给系统的变量不同而已。这可以在很大程度上降低数据库开发的工作量。这个变量在 Oracle 数据库系统中就叫做绑定变量。利用绑定变量可以加强与用户的互动性。另外在这个堆栈区内还保存着会话变量、 SQL 语句运行时的内存结构等重要的信息。

  通常情况下,这个堆栈区跟上面讲到的会话区一样,都可以让数据库系统进行自我维护,而管理员不用参与到其中。这些分区的大小,也是系统根据实际情况来进行自动分配的。当这个用户会话结束时,系统会自动释放这些区所占用的空间。

五、 游标区

  无论是 SQLServer 数据库还是 Oracle 数据库中,有时候都需要用到游标技术。当运行使用游标的语句时, Oracle 数据库系统会在程序缓存区中间为其分配一块区域。这块区域就叫做游标区。通常情况下,游标用来完成一些比较特殊的功能。而且一般来说,采用游标的语句要比其他语句的执行效率低一点。为此管理员在使用游标的时候,还是需要慎重。

  游标区是一个动态的区域。当用户执行游标语句时,系统就会在这个游标区内创建一个区域。当关闭游标时,这个区域就会被释放。这创建与释放,需要站用一定的系统资源,花费一定的时间。为此在使用游标时,如果频繁的打开和关闭游标,就会降低语句的执行性能。所以笔者建议,在写语句时,如果真的有必要使用游标技术时,则要注意游标不要频繁的打开和关闭。

  另外在 Oracle 数据库中,还可以通过限制游标的数量来提高数据库的性能。如在数据库系统中有一个初始化参数 OPEN_CURSORS 。管理员可以根据实际的需要,来设置这个参数,控制用户能够同时打开游标的数目。不过需要注意的是,在确实需要才有游标的情况下,如果硬件资源能够支持的话,那么就需要放宽这个限制。这可以避免用户进程频繁的打开和关闭游标。因为频繁的打开和关闭游标这对游标的操作是不利的,会影响数据库的性能。

从以上的分析中可以看出,程序全局区主要包含排序区、会话区、堆栈区和游标区四个部分的内容,他们各司其职,完成用户进程与数据库之间的会话。通常情况下,系统管理员主要关注的是排序区,在必要时需要手工调整这个排序区的大小。另外需要主要的是,游标区是一个动态的区域,在游标打开时创建,关闭时释放。故在数据库开发时,不要频繁的打开和关闭游标可以提高游标操作的效率,改善数据库的性能。其他分区的内容管理员只需要了解其用途,日常的维护交给数据库系统来完成即可。

使用这个新特性,
(1) oracle 可以自动调整 sql 内存区。
(2) the sort_area_size 等参数 is ignored by all the sessions running 。
  在 oracle9i 中, pga_aggregate_target 参数仅对专用服务器模式下( dedicated server )的专属连接有效,对共享服务器( shared server )连接无效;从 oracle10g 开始 pga_aggregate_target 对专用服务器连接和共享服务器连接同时生效。
  1. pga_aggregate_target- 此参数用来指定所有 session 总计可以使用最大 pga 内存。这个参数可以被动态的更改 , 取值范围从 10m -- ( 4096g-1 ) bytes 。
  2. workarea_size_policy- 此参数用于开关 pga 内存自动管理功能,该参数有两个选项: auto 和 manual ,当设置为 auto 时,数据库使用 oracle9i 提供的自动 pga 管理功能,当设置为 manual 时,则仍然使用 oracle9i 前手工管理的方式。
缺省的, oracle9i 中 workarea_size_policy 被设置为 auto 。

  单个 sql 操作能够使用的 pga 内存按照以下原则分配:
  1 .对于串行操作
  min ( 5% pga_aggregate_target ,100mb )
  2 .对于并行操作
  30% pga_aggregate_target /dop ( dop=degree of parallelism 并行度)
  启用了自动 pga 调整之后, oracle 仍然需要遵循以下原则:
  untunable memory size + tunable memory size <= pga_aggregate_target
  对于 pga_aggregate_target 参数的设置, oracle 提供这样一个建议方案
  1 .对于 oltp 系统
  pga_aggregate_target = (<total physical memory > * 80%) * 20%
  2 .对于 dss 系统
  pga_aggregate_target = (<total physical memory > * 80%) * 50%

  一段描述
  在 9i 之前,我们主要是通过设置 sort_area_size 、 hash_area_size 等参数值(通常都叫做 *_area_size )来管理 PGA 的使用,不过严格说来,是对 PGA 中的 UGA 中的私有 SQL 区域进行管理,这块内存区域又有个名称叫做 SQL 工作区域。但是,这里有个问题,就是这些参数都是针对某个 session 而言的,也就是说设置的参数值对所有连进来的 session 都生效。在数据库实际运行过程中,总有些 session 需要的 PGA 多,而有些 session 需要的 PGA 少。如果都设置一个很小的 *_area_size ,则会使得某些 SQL 语句运行时由于需要将临时数据交换到磁盘而导致效率低下。而如果都设置一个很大的值,又有可能一方面浪费空间,另一方面,消耗过多内存可能导致操作系统其他组件所需要的内存短缺,而引起数据库整体性能下降。所以如何设置 *_area_size 的值一直都是 DBA 很头疼的一个问题。
  而从 9i 起所引入的一个新的特性可以有效的解决这个问题,这个特性就是自动 PGA 管理。 DBA 可以根据数据库的负载情况估计所有 session 大概需要消耗的 PGA 的内存总和,然后把该值设置为初始化参数 pga_aggregate_target 的值即可。 Oracle 会按照每个 session 的需要为其分配 PGA ,同时会尽量维持整个 PGA 的内存总和不超过该参数所定义的值。这样的话, oracle 就能尽量避免整个 PGA 的内存容量异常增长而影响整个数据库的性能。从而,就有效的解决了设置 *_area_size 所带来的问题。



-- 预备知识
PGA(Process Global Area) ,是 server process 一段私有内存区,它包含有全局变量,数据结构和一些控制信息。在 Oracle8i 中, PGA 调整非常复杂,要调整 SORT_AREA_SIZE 、 HASH_AREA_SIZE 、 BITMAP_MERGE_AREA_SIZE 、 CREATE_BITMAP_AREA_SIZE 等参数。在 ORACLE9I 中,只需要调整 PGA_AGGREGATE_TARGET 。
具体参数:
SQL> SHOW PARAMETER SORT_AREA_SIZE;

NAME                                 TYPE        VALUE
------------------------------------ ----------- --------
sort_area_size                        integer     524288

SQL> SHOW PARAMETER HASH_AREA_SIZE;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------
hash_area_size                       integer     1048576

SQL> SHOW PARAMETER BITMAP_MERGE_AREA_SIZE;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------
bitmap_merge_area_size               integer     1048576

SQL> SHOW PARAMETER CREATE_BITMAP_AREA_SIZE;

NAME                                  TYPE        VALUE
------------------------------------ ----------- ------------------------------
create_bitmap_area_size              integer     8388608

SQL> SHOW PARAMETER PGA_AGGREGATE_TARGET;

NAME                                  TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 25165824

--PGA_AGGREGATE_TARGET 初始化设置

PGA_AGGREGATE_TARGET 的值应该基于 Oracle 实例可利用内存的总量来设置,这个参数可以被动态的修改。假设 Oracle 实例可分配 4GB 的物理内存,剩下的内存分配给操作系统和其它应用程序。你也许会分配 80 %的可用内存给 Oracle 实例,即 3.2G 。现在必须在内存中划分 SGA 和 PGA 区域。

在 OLTP 系统中,典型 PGA 内存设置应该是总内存的较小部分(例如 20 %),剩下 80 %分配给 SGA 。
OLTP : PGA_AGGREGATE_TARGET = (total_mem * 80%) * 20%

在 DSS 系统中,由于会运行一些很大的查询,典型的 PGA 内存最多分配 70 %的内存。
DSS : PGA_AGGREGATE_TARGET = (total_mem * 80%) * 50%

在这个例子中,总内存 4GB , DSS 系统,你可以设置 PGA_AGGREGATE_TARGET 为 1600MB , OLTP 则为 655MB 。

-- 配置 PGA 自动管理

不用重启 DB ,直接在线修改。

SQL> alter system set workarea_size_policy=auto scope=both;

System altered.

SQL> alter system set pga_aggregate_target=512m scope=both;

System altered.

SQL> show parameter workarea

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy                 string      AUTO -- 这个设置成 AUTO
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                  big integer 536870912

-- 监控自动 PGA 内存管理的性能

V$PGASTAT :这个视图给出了一个实例级别的 PGA 内存使用和自动分配的统计。

SQL> set lines 256
SQL> set pages 42
SQL> SELECT * FROM V$PGASTAT;

NAME                                                                   VALUE UNIT
---------------------------------------------------------------- ---------- ------------
aggregate PGA target parameter                                    536870912 bytes    -- 当前 PGA_AGGREGATE_TARGET 的值
aggregate PGA auto target                                         477379584 bytes    -- 当前可用于自动分配了的 PGA 大小,不应该比 PGA_AGGREGATE_TARGET 小
global memory bound                                                26843136 bytes    -- 自动模式下工作区域的最大大小, Oracle 根据工作负载自动调整。
total PGA inuse                                                     6448128 bytes
total PGA allocated                                                 11598848 bytes    --PGA 的最大分配
maximum PGA allocated                                             166175744 bytes
total freeable PGA memory                                            393216 bytes    --PGA 的最大空闲大小
PGA memory freed back to OS                                         69074944 bytes
total PGA used for auto workareas                                         0 bytes    --PGA 分配给 auto workareas 的大小
maximum PGA used for auto workareas                                 1049600 bytes
total PGA used for manual workareas                                       0 bytes
maximum PGA used for manual workareas                                530432 bytes
over allocation count                                                  1118  
-- 实例启动后,发生的分配次数,如果这个值大于 0 ,就要考虑增加 pga 的值
bytes processed                                                   114895872 bytes
extra bytes read/written                                            4608000 bytes
cache hit percentage                                                  96.14 percent    -- 命中率

16 rows selected.

--V$PGA_TARGET_ADVICE

SQL> SELECT round(PGA_TARGET_FOR_ESTIMATE/1024/1024) target_mb,
   ESTD_PGA_CACHE_HIT_PERCENTAGE cache_hit_perc,
   ESTD_OVERALLOC_COUNT
   FROM v$pga_target_advice;

The output of this query might look like the following:

TARGET_MB   CACHE_HIT_PERC ESTD_OVERALLOC_COUNT
---------- -------------- --------------------
63       23          367
125        24          30
250        30           3
375        39          0
500        58          0
600        59          0
700        59          0
800        60          0
900        60          0
1000    61          0
1500    67          0
2000    76          0
3000    83          0
4000    85           0

可以看出当 TARGET_MB 为 375M 是 ESTD_OVERALLOC_COUNT=0 ,所以我们可以将 PGA_AGGREGATE_TARGET 设置成 375M


主要总结下 pga 分配算法 , 详细概念单总结

简单理解 pga,pga 就是一个操作系统进程 , 或线程 (WIN 上 ) 的专用内存
pmon,smon 这些后台进程都有自己的 pga


pga 早期手动管理组成由 sort_area_size,hash_area_size,bitmap_merge_size,create_bitmap_area_size( 这些都叫工作区 )
手动缺点,不好回收和共享,会造成 PGA 内存过度消耗

PAG 自动( 9i 开始支持)
1.pga_aggregate_target 来指定所有 session 总计可以使用的最大 pga 内存( 10M-4096G )
2.workarea_size_policy 控制 pag 自动管理功能开启或关闭, auto 表示开启( default ), manual 表示关闭, 9i auto 只支持专用连接,共享连接不支持
10g 都支持

_pga_max_size: 控制 pga 最大大小
9i-10r1 中 , 单个 sql 操作内存使用现在
1. 对于串行操作 , 单 sql 操作 pga 分配原则 ,min(5%*pga_aggregate_target,100mb)
########5%*pga_aggregate_targe 实际由 _smm_max_size 控制 ]
2. 并行操作使用 pga 按 30%*pga_aggregate_target/dop(dop= 并行度 )




9I _pga_max_size 与 _smm_max_size
_pga_max_size>5%*pga_aggregate_target,_smm_max_size=5%*pga_aggregate_target'
_pga_max_size<5%*pga_aggregate_target,_smm_max_size=50*_pga_max_size

used_pga_mb=min(5%*pga_aggregate_target,50*_pga_max_size,_smm_max_size)

10r2,11g 原则
1. 串行操作
pga_aggregate_target<=500MB,_smm_max_size=20%*pga_aggregate_target
pga_aggregate_target between 500m and 1000M ,_smm_max_size=100M
pga_aggregate_target between 1001m and 2.5g,_smm_max_size=10%*pga_aggregate_target
pga_aggregate_target >2.5g,_smm_max_size=0.25GB
2. 并行操作
50*pag_aggregate_target/dop
dop<=5 时 ,_smm_max_size 生效
dop>5 时 ,_smm_px_max_size 生效

_newsort_enabled  控制算法规则 ,true 用 10g 新算法 ,false 用 9i 算法
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: newsort
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%newsort%'

NAME                            VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_newsort_enabled               TRUE
controls whether new sorts can be used as system sort

设置建议
1.oltp 系统 pag_aggregate_target=<total physical memory>*80%*20%
2.dss 系统   pag_aggregate_target=<total physical memory>*80%*50%
分析 : 留 20% 给 os, 其他 80% 给 pga+sga,oltp ,pga 占 80% 中 20%,dss 占 80% 中 50%

# 查看某个 process 使用情况
select pid,spid,username ,pga_used_mem,pga_alloc_mem,pga_freeable_mem,pga_max_mem,program from v$process where spid=&spid

SQL> select pid,spid,username ,pga_used_mem,pga_alloc_mem,pga_freeable_mem,pga_max_mem,program from v$process where spid=&spid;
Enter value for spid: 25510
old   1: select pid,spid,username ,pga_used_mem,pga_alloc_mem,pga_freeable_mem,pga_max_mem,program from v$process where spid=&spid
new   1: select pid,spid,username ,pga_used_mem,pga_alloc_mem,pga_freeable_mem,pga_max_mem,program from v$process where spid=25510

       PID SPID                     USERNAME        PGA_USED_MEM PGA_ALLOC_MEM
---------- ------------------------ --------------- ------------ -------------
PGA_FREEABLE_MEM PGA_MAX_MEM PROGRAM
---------------- ----------- ------------------------------------------------
        33 25510                    oracle                     0       2664666
          983040     8431834oracle@dmk01(PZ98)

pga_used_mem: 进程使用的 pga
pga_alloc_mem: 分配给进程的 pga
pga_freeable_mem: 空闲
pga_max_mem: 进程使用 pga 内存的最大




# 查看 pga 消耗到哪些项目上了
col program for a20
set linesize 1000
select p.program,p.pid,pm.category,pm.allocated,pm.used,pm.max_allocated from v$process p,v$process_memory pm where p.pid=pm.pid and p.spid=&spid;


SQL> col program for a20
SQL> set linesize 1000
SQL> select p.program,p.pid,pm.category,pm.allocated,pm.used,pm.max_allocated from v$process p,v$process_memory pm where p.pid=pm.pid and p.spid=&spid;
Enter value for spid: 25510
old   1: select p.program,p.pid,pm.category,pm.allocated,pm.used,pm.max_allocated from v$process p,v$process_memory pm where p.pid=pm.pid and p.spid=&spid
new   1: select p.program,p.pid,pm.category,pm.allocated,pm.used,pm.max_allocated from v$process p,v$process_memory pm where p.pid=pm.pid and p.spid=25510

PROGRAM                     PID CATEGORY         ALLOCATED       USED MAX_ALLOCATED
-------------------- ---------- --------------- ---------- ---------- -------------
oracle@dmk01(PZ98)          33 SQL                      0          0       2424808
oracle@dmk01(PZ98)          33 PL/SQL               24840      17104         26928
oracle@dmk01(PZ98)          33 Freeable            983040          0
oracle@dmk01(PZ98)          33 Other              1656786                  4997058



sql 在 workare 中有 3 种方式
1.optimal: 最优方式 , 所有处理可以在内存中完成
2.onepass: 大部分操作可以在内存中完成 , 但交换到临时表一次
3.multipass: 多变交互临时表 , 产生大量 disk sort 之类 , 性能最差

oracle 建议
workarea execution_optimal>=90%
workarea execution_multipass=0%
# 查看系统中性能指标
select name,value,100*(value/decode((select sum(value) from v$sysstat where name like 'workarea execution%'),0,null,(select sum(value) from v$sysstat where name like 'workarea execution%')))pct from v$sysstat where name like 'workarea executions%';


SQL> select name,value,100*(value/decode((select sum(value) from v$sysstat where name like 'workarea execution%'),0,null,(select sum(value) from v$sysstat where name like 'workarea execution%')))pct from v$sysstat where name like 'workarea executions%';

NAME                                                                   VALUE        PCT
---------------------------------------------------------------- ---------- ----------
workarea executions - optimal                                        567832 99.9954214
workarea executions - onepass                                            24 .004226409
workarea executions - multipass                                           0          0



# 查单个 sql 语句 workarea 使用情况
SELECT
b.sql_text,
a.operation_type,
a.policy,
a.last_memory_used/(1024*1024) as "Used MB" ,
a.estimated_optimal_size/(1024*1024) as "Est Opt MB",
a.estimated_onepass_size/(1024*1024) as "Est OnePass MB",
a.last_execution,
a.last_tempseg_size
FROM v$sql_workarea a,v$sql b
WHERE a.hash_value = b.hash_value
  and a.hash_value = &hashvalue
/

# 查 session 使用 pga
select a.name, b.value
from v$statname a, v$sesstat b
where a.statistic# = b.statistic#
and b.sid = &sid
and a.name like '%ga %'
order by a.name
/

#program 使用 pga 情况
SELECT
   a.pga_used_mem "PGA Used",
   a.pga_alloc_mem "PGA Alloc",
   a.pga_max_mem "PGA Max"
  FROM v$process a,v$session b
where a.addr = b.paddr
  and b.sid= &sid
/





关于 pga 自动管理算法:
oracle 采用的 feedback loop 实现的,当一个 process 执行 sql 语句时 , 先用 local memory manager 注册一个 active workarea profile,workarea profile 是与内存管理器之间唯一的通信接口
( 既 sql 语句和内存管理器之间唯一接口 ), 当 sql 语句执行完成对应的 workarea profile 删除
,profile 含这个 workarea 很多属性(例如 sql 类型是 hash join 还是什么之类,执行 one pass,optimal 操作内存大小等的元数据)
workarea active profile 集,通过 local memory manager 维护,存 sga 中 ,profile 常常被更新 ( 要求及时反映 sql 语句当前已消耗内存,及是否被交换到 temp tablespace 等信息 ) ,
所以 active profile 基本上就是 pga 内存需要和当前正在使用的 pga 内存 , 通过这些 profile 信息
,global memory manager 会计算出一个既可以限制内存使用又可以提高较好性能的 global memory bound, 这个值用于限制单个进程 pga 的上限, global memory manager 每 3S 更新一次 memory
bound,local memory manager 得到 memory bound 后会计算每个 active statement 所需要分配的 pga 内存大小( execute size ),然后每个 active statement 将会在自己所分配到的 execute size
中计算




路线 ( 一个环路 )
active statement---> 注册 workarea profile-->local memory manager( 存 sga 中 )-->set of active workarea profiles-->global memory manager---> 计算出 memory bound--->local memory manager
---> 获取 workarea size--->active statement

其实原理很简单,就是每个 sql 语句拿出信息做成 profile ,然后交给 local memory manager 然后做成 profile 集(大量 profile ),然后 global memory manager 通过 profile 集计算出 memory bound
,把这个 memory bound 给   local memory manager , local memory manager 用 memory bound 计算出每个 active statement 的 execute size ,然后每个 active statement 在自己分到的 execute
size 中计算


global memeory bound 将影响 所有进程 pga 分配(限制单个进程 pga 的上限)




由 ckpt 实现 ,global memory manager 3s 更新一次 memory bound

SQL> select description ,dest from x$messages where lower(description) like 'sql memory%';

DESCRIPTION
----------------------------------------------------------------
DEST
----------------------------------------------------------------
SQL Memory Management Calculation
CKPT



SQL> select time,data from x$trace where lower(data) like '%sql memory%' order by seq#;

      TIME
----------
DATA
--------------------------------------------------------------------------------
1.2688E+15
KSBCTI: (CKPT) : (timeout action)    : acnum=[178] comment=[SQL Memory Management
  Calculation]

1.2688E+15
KSBCTI: (CKPT) : (timeout action)   : acnum=[178] comment=[SQL Memory Management
  Calculation]

1.2688E+15

      TIME
----------
DATA
--------------------------------------------------------------------------------
KSBCTI: (CKPT) : (timeout action)   : acnum=[178] comment=[SQL Memory Management
  Calculation]




10g r2,11g 中, workarea 管理内存分配,存在 shared pool 中( local memory manager )
SQL> select * from v$sgastat where name like 'work area%';

POOL         NAME                            BYTES
------------ -------------------------- ----------
shared pool  work area tab                   265320








10g  测试



SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0      Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production



SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  209715200
Maximum size of the PGA memory for one process

可以看到当 pga_aggreate_target 小于 1g,_pga_max_size 默认为 200MB

SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  26214
maximum work area size in auto mode (serial)

pga_aggregate_target <500M,_smm_max_size 默认为 20%pga_aggregate_target=25.6M( 其实 _smm_max_size 实际与 _pga_max_size 还有关系 , 单相关算发已经不是 9i 的了 , 下面会证实 )


SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 128M
SQL>


SQL> select 26214/1024 from dual;

26214/1024
----------
25.5996094

SQL> select 0.2*128 from dual;

   0.2*128
----------
      25.6

_smm_max_size = 20%*pga_aggregate_target




修改 _pga_max_size=10MB  pga_aggregate_target =128M

SQL> alter system set "_pga_max_size"=10m;

System altered.

SQL> startup force    重起下库 , 让内存重新计算
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size              100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> drop table t;

Table dropped.

SQL> create table t as select * from dba_objects;

Table created.

SQL> insert into t select * from dba_objects;

50067 rows created.

SQL> insert into t select * from dba_objects;

50067 rows created.

SQL> commit;

Commit complete.

SQL> select distinct sid from v$mystat;

       SID
----------
       159

SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size                        big integer 10M
pga_aggregate_target                 big integer 128M
SQL> set linesize 132
column name format a30
SQL> SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  10485760     
Maximum size of the PGA memory for one process
可以看到已经生效 , 单位字节 =10M

SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  5120
maximum work area size in auto mode (serial)

可以看到 _smm_max_size  此时并不等于 20%*pga_aggregate_target 而是 =5m 既 50%_pga_max_size




SQL> select 10485760/1024/1024 from dual;

10485760/1024/1024
------------------
                10


SQL> select 5120/1024 from dual;

  5120/1024
----------
         5
       

SQL> set autotrace traceonly stat
SQL> select * from t where rownum<50000 order by 1,2,3,4,5,6,7;

49999 rows selected.


Statistics
----------------------------------------------------------
         37  recursive calls
          8  db block gets
        835  consistent gets
       1382  physical reads
          0  redo size
    2837037  bytes sent via SQL*Net to client
      37063  bytes received via SQL*Net from client
       3335  SQL*Net roundtrips to/from client
          0  sorts (memory)
          1  sorts (disk)
      49999  rows processed






SQL> select hash_value from v$sql where sql_text='select * from t where rownum<50000 order by 1,2,3,4,5,6,7'
  2  ;

HASH_VALUE
----------
1281487883

SQL> SELECT
b.sql_text,
  2    3  a.operation_type,
  4  a.policy,
  5  a.last_memory_used/(1024*1024) as "Used MB" ,
  6  a.estimated_optimal_size/(1024*1024) as "Est Opt MB",
  7  a.estimated_onepass_size/(1024*1024) as "Est OnePass MB",
  8  a.last_execution,
  9  a.last_tempseg_size
  10  FROM v$sql_workarea a,v$sql b
  11  WHERE a.hash_value = b.hash_value
  12    and a.hash_value = &hashvalue
  13  /
Enter value for hashvalue: 1281487883
old  12:   and a.hash_value = &hashvalue
new  12:   and a.hash_value = 1281487883

SQL_TEXT
--------------------------------------------------------------------------------
OPERATION_TYPE       POLICY        Used MB Est Opt MB Est OnePass MB LAST_EXECU
-------------------- ---------- ---------- ---------- -------------- ----------
LAST_TEMPSEG_SIZE
-----------------
select * from t where rownum<50000 order by 1,2,3,4,5,6,7
SORT (v2)            AUTO       5.02832031 6.09960938      .98828125 1 PASS
          6291456

可以看到内存被限制在 5M 内 , 现在操作是 1 pass, 如果 最优操作 ( 全在内存里 需要 6M)
所以 _smm_max_size 就可以限制一个 process pga 内存 最大使用


此时 _smm_max_size=5m 是如下计算
1._pga_max_size<40%*pga_aggregate_size, 此时 _smm_max_size=50%_pga_max_size
2._pga_max_size>40%*pga_aggregate_siz, 此时 _smm_max_size 按下面方式计算

pga_aggregate_target<=500MB,_smm_max_size=20%*pga_aggregate_target
pga_aggregate_target between 500m and 1000M ,_smm_max_size=100M
pga_aggregate_target between 1001m and 2.5g,_smm_max_size=10%*pga_aggregate_target
pga_aggregate_target >2.5g,_smm_max_size=0.25GB




修改 pga_aggregate_target 超过 500m
SQL> alter system set pga_aggregate_target=501m;

System altered.

SQL> startup force
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size                        big integer 10M  ~~~~~~~~~ 还未 10MB
pga_aggregate_target                 big integer 501M
SQL>




SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
SQL>   2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                            VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  10485760
Maximum size of the PGA memory for one process


SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  5120 ~~~~~~~~~~~~~~~ 还为 5M 单位 kb
maximum work area size in auto mode (serial)

通过这个可以发现 影响 _smm_max_size 调整最直接相关的参数为 _pga_max_size, 由于 _pga_max_size 未调整 . _smm_max_size 没变
所以可以得出结论 pga_aggreate_target 影响 _pga_max_size,_pga_max_size 影响 _smm_max_size

可以看到 虽然 pga_aggregate_target 设置了 501M,_PGA_MAX_SIZE 应该为 200M 自动调整为,但由于 _pga_max_size 手动调整的,所以要手动 reset 下 让它自动默认(这样就自动计算了)
SQL> alter system reset "_pga_max_size" scope=spfile sid='*' ;

System altered.

SQL> startup force
ORACLE instance started

Total System Global Area  268435456 bytes
Fixed Size                   1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  209715200    ~~~~~~~~~
Maximum size of the PGA memory for one process

按算发 pga_aggreate_target<1g,_pga_max_size =200m

SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  102400
maximum work area size in auto mode (serial)


SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 501M
SQL>

102400/1024=100MB 正好 100MB
可以看到 _pga_max_size=200M(pga_aggreate_target<1g,_pga_max_size default =200m) ,按表面算法 pga_aggreate_target>500M  _smm_max_size   为 100MB
而实际内部因为
_pga_max_size=200M<40%*pga_aggregate_target, 所以 _smm_max_size  =100M ( 50%*_pga_max_size )
(pga_aggreate_target 影响 _pga_max_size,_pga_max_size 影响 _smm_max_size)
有时候 手动修改 _pga_max_size 后 ,如果要让算法继续执行,需要 reset 下,否则不使用算法了 .



改 pga_aggregate_target<500M
SQL> alter system set pga_aggregate_target=499m;

System altered.

SQL> startup force
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  209715200
Maximum size of the PGA memory for one process


SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  102195
maximum work area size in auto mode (serial)


SQL> select 102195/1024 from dual;

102195/1024
-----------
  99.7998047  _smm_max_size=99.8m,_pga_max_size  =200M

SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 499M
SQL> select 499*0.2 from dual;

   499*0.2
----------
      99.8
   
SQL> select 0.4*499 from dual;

   0.4*499
----------
     199.6

分析   _pga_max_size >40%pga_aggregate_target , 所以 _smm_max_size=20%*pga_aggregate_target =99.8M



手动改 _pga_max_size 为 300M,pga_aggregate_target=501M
SQL> alter system set "_pga_max_size"=300M SCOPE=SPFILE;

System altered.

SQL> startup force;
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  314572800
Maximum size of the PGA memory for one process


SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  102604
maximum work area size in auto mode (serial)



SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size                         big integer 300M
pga_aggregate_target                 big integer 501M
SQL>
SQL> select  102604/1024 from dual;

102604/1024
-----------
  100.199219


SQL> select 0.2*501 from dual;

   0.2*501
----------
     100.2


分析
_pga_max_size>40%*pga_aggregate_target,
按算法 pga_aggregate_target>500M<1G,_smm_max_size =100MB( 按 pga_aggregate_target between 500m and 1000M ,_smm_max_size=100M), 但实际还是按
_pga_max_size>40%*pga_aggregate_target,_smm_max_size=20%*pga_aggregate_target =100.2m


做一个极端的 ,_pga_max_size=600M,pga_aggregate_target=700M, 如果按 pga_aggregate_target between 500m and 1000M 那么 _smm_max_size=100M, 实际会是这样吗 ?


SQL> alter system set "_pga_max_size"=600m;

System altered.

SQL> alter system set pga_aggregate_target=700m;

System altered.

SQL> startup force
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size                        big integer 600M
pga_aggregate_target                 big integer 700M
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL>
SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  143360
maximum work area size in auto mode (serial)


可以看到 _smm_max_size=140G 没有按 ,pga_aggregate_target>500M<1G 时候应该 =100m,_pga_max_size>40%*pga_aggregate_target, 而是按 20%*pga_aggreget_target 算的 =140G 了














设置 _pga_max_size=199g,pga_aggregate_target=501g
SQL> alter system set "_pga_max_size"=199M SCOPE=SPFILE;

System altered.

SQL> startup force
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size                         big integer 199M
pga_aggregate_target                 big integer 501M
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                            VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  101888
maximum work area size in auto mode (serial)


SQL> select 101888/1024 from dual;

101888/1024
-----------
       99.5~~~~~~~~~~~~~~~

分析 _pga_max_size<40%pga_aggregat_target, 所以 _smm_max_size=50%_pga_max_size

SQL> alter system set "_pga_max_size"=99M SCOPE=SPFILE;

System altered.

SQL> startup force
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                  1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                 7118848 bytes
Database mounted.
Database opened.
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3       WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  103809024
Maximum size of the PGA memory for one process


SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  50688           
maximum work area size in auto mode (serial)


SQL> select 103809024/1024/1024 from dual
  2  ;

103809024/1024/1024
-------------------
                 99

SQL> select  50688 /1024 from dual;

50688/1024
----------
      49.5
_smm_max_size =      49.5

分析 _pga_max_size<40%pga_aggregat_target, 所以 _smm_max_size=50%_pga_max_size




有文挡说 _smm_max_size 最大 0.25GB, 实际是这样吗
SQL> alter system set pga_aggregate_target=2g; 修改为 2g

System altered.

SQL> startup force;
ORACLE instance started.

Total System Global Area  268435456 bytes
Fixed Size                   1266944 bytes
Variable Size             100666112 bytes
Database Buffers          159383552 bytes
Redo Buffers                7118848 bytes
Database mounted.
Database opened.
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  419430400
Maximum size of the PGA memory for one process


_pga_max_size  =20%*pga_aggreaget_target=400m
SQL> /
Enter value for par: smm_max
old   3:      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  204800
maximum work area size in auto mode (serial)

_pga_max_size<40%pga_aggregate_target, 所以 _smm_max_size=50%*_pga_max_size=200m

文档中当 pga_aggrgate_target >1G 情况时 , 其实还是按上面的 计算方式
_pga_max_size=20%*pga_aggregate_target
_smm_max_size=10%*pga_aggregate_target

一套负责的生产库中 pga (11g,11.1.0.7)
SQL> show parameter target

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
archive_lag_target                   integer     0
db_flashback_retention_target        integer     1440
fast_start_io_target                 integer     0
fast_start_mttr_target                integer     0
memory_max_target                    big integer 0
memory_target                        big integer 0  ********************** 没开
SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 30G
SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL>
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  2147483648
Maximum size of the PGA memory for one process


SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                            VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  1048576

可以看到 _smm_max_size 早就超过了 250M 到达了 1G, 这个数是根据 _pga_max_size 决定
当 pga_aggreate_size>1g 时候 ,_pga_max_size=20%*pga_aggreate_size(pga_aggreate_size>10g 时 ,_pga_max_size 不变 )
_pga_max_size=20%*10g<40%*pga_aggreaget_size, 所以 _smm_max_size=50%*_pga_max_size=1g

总结 10g r2

PGA_AGGREATE_TARGET 与 _smm_max_size
pga_aggregate_target<=500MB,_smm_max_size=20%*pga_aggregate_target
pga_aggregate_target between 500m and 1000M ,_smm_max_size=100M
pga_aggregate_target between 1001m and 2.5g,_smm_max_size=10%*pga_aggregate_target





pga_aggregate_target,_pga_max_size 关系
_pga_max_size 如果 pga_aggregate_target<1g _pga_max_size= 默认 200MB
_pga_max_size 如果 pga_aggregate_target>1g,_pga_max_size=20%*pga_aggregate_target(>5G 不再变化 )

  实际到内部
_smm_max_size 为实际控制单个 process 使用 pga 上限 , 唯一可以相关他的参数是 _pga_max_size,_pga_max_size 被 pga_aggregate_target 相关
_pga_max_size<40%*pga_aggregate_target,_smm_max_size=50%*_pga_max_size ,
其他时候( _pga_max_size>40%*pga_aggregate_target ) _smm_max_size=20%PGA_AGGREGATe_TARGET




具体 process 可以使用的 pga 就是由 _smm_max_size 控制


> "_pga_max_size" is 200M by default.

That was true up to Oracle 10.1. Since 10.2 it is a dynamic parameter.

In 10.2 it is limited to 200M as long as pga_aggregate_target is smaller as 1GB.
When pga_aggregate_target is set to a larger value as 1GB then _pga_max_size= 20% of pga_aggregate_target .

> Is 350M of "pga_aggregate_target" effective even when "_pga_max_size" is 200M?
Yes it is still effective. The size of one work area (hash area, sort area) is not directly limited by _pga_max_size but by _smm_max_size (unit of this parameter is KBytes!). When you set pga_aggregate_target to 350M _smm_max_size should have a value like 71680 (71680KB => 70MB).







随着版本的变化内存管理也发生变化

11g 内存管理更加简单了
只要设置 memory_target=PGA+SGA 这叫做 amm 特性, automatic memory management
设置后取代了 pga_aggregate_target,sga_target, 原理跟设置 sga_target 一样, _pga_aggregate_target,_sga_target 表示数据库上次正常关闭时候内存分配的样子

oracle 启动时候 会用 pga_aggregate_target,sga_target 与 _pga_aggregate_target,_sga_target, 谁的值大用谁


SQL> show parameter target

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
archive_lag_target                   integer     0
db_flashback_retention_target        integer     1440
fast_start_io_target                 integer     0
fast_start_mttr_target               integer     0
memory_max_target                    big integer 476M
memory_target                        big integer 476M   ****************************
pga_aggregate_target                 big integer 60M
sga_target                            big integer 0



SQL> set linesize 132
SQL> column name format a30
SQL> column value format a25
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2     FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3      WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
  4
SQL>
SQL> /
Enter value for par: pga_aggrega
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_aggrega%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
pga_aggregate_target           62914560
Target size for the aggregate PGA memory consumed by the instance

__pga_aggregate_target         150994944
Current target size for the aggregate PGA memory consumed

可以看到实际 pga 为 150M
SQL> /
Enter value for par: pga_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%pga_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_pga_max_size                  209715200
Maximum size of the PGA memory for one process

可以看到 pga 小于 1g,_pga_max_size   默认为 200M

SQL> /
Enter value for par: smm_max
old   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:     WHERE x.indx = y.indx AND x.ksppinm LIKE '%smm_max%'

NAME                           VALUE
------------------------------ -------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------
_smm_max_size                  29491
maximum work area size in auto mode (serial)

_pga_max_size>40%__pga_aggregate_target 所以 ,_smm_max_size 按 __pga_aggregate_target 算法 ( 此例中小于 500M 那么 _smm_max_size=20*__pga_aggregate_target=30M).










# 查看 pga 建议
SELECT (SELECT ROUND(value/1024/1024,0) FROM v$parameter
WHERE name = 'pga_aggregate_target') "Current Mb"
, ROUND(pga_target_for_estimate/1024/1024,0) "Projected Mb"
, ROUND(estd_pga_cache_hit_percentage) "%"
FROM v$pga_target_advice
ORDER BY 2;




#PGA 常用的查询

-PGASTAT
max memory used per session = min(5%*pga_aggregate_target,50%*_pga_max_size,_smm_max_size)
_sort_multiblock_read_count

SELECT NAME,VALUE VALUE_INT FROM V$PGASTAT;

select last_execution,count(1) from v$sql_workarea where POLICY='AUTO' group by last_execution;

select sum(OPTIMAL_EXECUTIONS) OPTIMAL,sum(ONEPASS_EXECUTIONS) ONEPASS ,sum(MULTIPASSES_EXECUTIONS) MULTIPASSES
from v$sql_workarea where POLICY='AUTO';

SELECT LOW_OPTIMAL_SIZE/1024 low_kb,(HIGH_OPTIMAL_SIZE+1)/1024 high_kb,
       optimal_executions optimal, onepass_executions onepass, multipasses_executions multipasses
FROM   v$sql_workarea_histogram
WHERE  total_executions != 0;

select n.name,sum(s.value) value
from v$sesstat s,v$statname n where s.statistic#=n.statistic#
and n.name like 'workarea executions%'
group by n.name;

select n.name,sum(s.value) value
from v$sysstat s,v$statname n where s.statistic#=n.statistic#
and n.name like 'workarea executions%'
group by n.name;

SELECT round(PGA_TARGET_FOR_ESTIMATE/1024/1024) target_mb,
       ESTD_PGA_CACHE_HIT_PERCENTAGE cache_hit_perc,
       ESTD_OVERALLOC_COUNT
FROM   v$pga_target_advice;

SELECT   server, s.username, osuser, NAME, VALUE / 1024 / 1024, s.SID, s.serial#, spid
FROM v$session s, v$sesstat st, v$statname sn, v$process p
WHERE st.SID = s.SID
AND st.statistic# = sn.statistic#
AND sn.NAME LIKE 'session pga memory'
AND p.addr = s.paddr
AND VALUE > 10 * 1024 * 1024                                              --only show pga > 10M
ORDER BY VALUE DESC;

--PGA USAGE
SQL> select
sum(value)/1024/1024 Mb
from
v$sesstat s, v$statname n
where
n.STATISTIC# = s.STATISTIC# and
name = 'session pga memory';

  col name format a30
select
sid,name,value
from
v$statname n,v$sesstat s
where
n.STATISTIC# = s.STATISTIC# and
name like 'session%memory%'
order by 3 asc;

SQL> select sum(bytes)/1024/1024 Mb from
(select bytes from v$sgastat
union
select value bytes from
v$sesstat s,
v$statname n
where
n.STATISTIC# = s.STATISTIC# and
n.name = 'session pga memory'
);



# 接触过许多 9I 库PGA 给到 40 多G 但还是有不少多遍排序情况~原因就是 上面算法问题

你可能感兴趣的:(oracle)