为了执行在内存中存储数据的SQL操作(例如,排序操作和散列联接),会使用工作区。这些工作区在每个服务进程的私有内存(PGA)中进行分配。
通常,更大的工作区会提供更好的性能。因此,你应该将系统中可用的未分配内存用于工作区的分配中。但是,在修改它的时候要小心。工作区的大小也会对查询优化器的估算产生影响。可以预见的是,改变不仅会体现在性能方面,也会体现在执行计划上。换句话说,如果想避免意想不到的情况,那么所有的修改都应该是经过仔细测试的。
总的来说,本节不会为所描述的初始化参数提供“合理的”值。为某一个应用程序找出合理值的唯一办法,是测试并测量达到合理的性能所需要的PGA的大小。事实上,内存总量只对性能有影响而对一个操作该如何执行没有影响。
workarea_size_policy
workarea_size_policy初始化参数指定如何调整工作区大小的工作。可以将它设置为下面两个值中的一个。
Ø auto:单个工作区的大小调整委托给内存管理器。通过pga_aggregate_target初始化参数,只有整个系统的PGA总量被指定。这是默认值。
Ø manual:通过hash_area_size、sort_area_size、sort_area_retained_size以及bitmap_merge_area_size初始化参数,可以完全控制工作区大小的调整。
在大多数情形中,内存管理器运行良好,所以极力推荐将PGA的管理委托给它。只有在很少的情况下手工精心调整可以提供比自动PGA管理更好的结果。
workarea_size_policy初始化参数是动态的,并且可以在实例和会话级别修改。因此可以在系统级别启用自动PGA管理,然后对于特殊要求,在会话级别切换为手工PGA管理。在12.1版本的多租户环境下,也可以在PDB级别进行设置。
pga_aggregate_target
如果启用了自动PGA管理,pga_aggregate_target 参数指定(按字节)分配给一个数据库实例的PGA总量。支持的值的范围是从10MB~4TB。默认值是系统全局区(SGA)大小的20%。对于如何使用这个值很难给出任何具体的建议。但是,在所有的系统上,每个并发的会话至少需要几兆字节的内存。
注意自11.1版本开始,memory_target和memory_max_target初始化参数可以用于指定一个数据库实例使用的内存总量(也就是SGA大小加上合计的PGA大小)。设置了这两个参数之后,数据库引擎会自动按需要在SGA和PGA之间重新分配内存。在这样的配置中,pga_aggregate_target初始化参数仅用来设置PGA的最小值。
要说明内存管理器是如何工作的,我在11.2.0.3版本中执行了一个需要60MB左右PGA的查询并逐渐递增并发会话的数量(1~50)。对于每一次迭代,都检查由数据库实例分配的最大PGA总量,并查看由执行查询的会话分配的平均PGA总量。
pga_aggregate_target初始化参数被设置为1GB。这就意味着,如果目标兑现,应该最多有17个会话(1GB/60MB)能够获得必要的PGA从而在内存中执行整个语句。图9-5展示了测试的结果。正如你所看到的,数据库实例分配的最大PGA增长了,与配置的一样,达到了1GB。注意,在第19个并发会话之前,系统PGA与会话数差不多成比例增长。超过17个会话时,系统开始减少提供给每个会话的PGA总量。
一定要理解pga_aggregate_target初始化参数的值并非一个硬性限制,而是更倾向于一个目标值。因此,如果指定的值过低,则数据库引擎可以自由分配比指定的值更多的内存。之所以允许这样做是因为如果无法为操作分配请求的内存则会导致其失败。但是你仍然可以使用pga_aggregate_limit初始化参数(参见下一节)设置一个硬性限制。这个参数从12.1版本开始可用。在这之前的版本中它不可用。
为了展示一个数据库实例过度分配PGA的案例,我通过将pga_aggregate_target初始化参数设置为128MB重新运行之前的测试。换句话说,我指定的值远远不够运行50个每个都需要60MB内存的并发会话。图9-6显示了测试的结果。你可以看到,即便是单个会话也无法获取足够的PGA来在内存中执行查询。实际上,那个会话只获得了所需要内存的一半。随着并发会话数量的增加,越来越多的PGA被分配。到第50个会话的时候,使用了大约400MB的PGA--是配置的目标值的三倍还多。
要了解一个系统是否经历过PGA过度分配的情况,可以使用接下来针对v$pgastat视图的查询。(注意,查询的输出显示的是数据库实例运行完图9-6所示的测试之后的最终状态。)如果像显示的那样,maximum PGA allocated 的值远远高于 aggregate PGA
target_parameter 的值,就表示pga_aggregate_target
初始化参数的值不合适。
在这种情况下,重要的是要了解过度分配发生的频率。出于这个目的,over allocation count 统计信息表明数据库实例从上一次启动后不得不分配比通过pga_aggregate_target初始化参数指定的值更多的PGA的次数。理想情况下这个值应该是0:
select name, value, unit
FROM v$pgastat
WHERE name IN ('aggregate PGA target
parameter',
'maximum PGA allocated',
'over allocation count');
你还可以通过v$pgastat视图获得关于当前分配的PGA总量,以及它们中有多少是用于自动或手工工作区的信息。下面的查询说明了这一点。注意尽管拥有total前缀的统计数据提供了当前的使用情况,拥有maximum前缀的统计数据会提供自上一次数据库实例启动以来的最高使用情况:
select name, value, unit
FROM v$pgastat
WHERE name LIKE '% PGA allocated' OR name
LIKE '% workareas';
还要注意,在这个输出当中,分配的PGA只有一部分是用于工作区。很明显,还有其他的东西存储在PGA中。关键点是,每个请求一些内存来执行SQL语句或PL/SQL子程序的进程都能够分配一部分通过pga_aggregate_target初始化参数配置的PGA。即使这些内存在不用于工作区的情况下也可以完成分配。
因为内存管理器无法控制这些附加的内存结构(又称为无法调整的内存)的大小,部分PGA也不在内存管理器的控制下。因此,根据系统负载,工作区可用的PGA总量会随时间而变化。在任意给定的时刻可以通过 aggregate PGA
auto target 统计信息查看可用的内存总量。接下来的例子是来自pga_auto_target.sql脚本输出的一段摘录,显示了如何通过PL/SQL调用定义的收集操作来分配500MB的PGA,进而减少工作区可用的内存总量:
SELECT name, value, unit
FROM v$pgastat
WHERE name LIKE 'aggregate PGA %';
execute pga_pkg.allocate(500000);
SELECT name, value, unit
FROM v$pgastat
WHERE name LIKE 'aggregate PGA %';
execute dbms_session.reset_package;
SELECT name, value, unit
FROM v$pgastat
WHERE name LIKE 'aggregate PGA %';
pga_aggregate_target 初始化参数是动态的,并且可以在实例级别修改。在12.1版本的多租户环境下,也可以在PDB级别进行设置。