This is a interesting feature for Oracle DBA’s. Till now there has been no way of limiting total PGA being used by oracle instance. _pga_max_size (hidden parameter) could be used to limit per process memory. SGA_TARGET used to be hard limit for Oracle SGA but PGA_AGGREGATE_TARGET only controlled allocation of PGA memory to each process via oracle algorithm. (I know some folks who thought pga_aggregate_target is hard limit, but that is incorrect)
Due to this many times we end up in a situation when we get paged for High CPU /Low memory utilization and found that high swapping was being caused by excessive PGA usage. Since kswapd (linux) is busy writing to swap, you will also see high CPU utilization.
At this moment, your memory might look like below
$free -m total used free shared buffers cached Mem: 16057 15953 103 0 4 209 -/+ buffers/cache: 15739 317 Swap: 12287 5359 6928
PGA_AGGREGATE_LIMIT is supposed to put a hard limit on the PGA Memory usage. But unlike SGA_TARGET, this doesn’t mean that processes will reduce the memory consumption. Instead this will lead to process/session failure.
As per Oracle docs oracle will terminate sessions in following order
-Calls for sessions that are consuming the most untunable PGA memory are aborted.
– If PGA memory usage is still over the PGA_AGGREGATE_LIMIT, then the sessions and processes that are consuming the most untunable PGA memory are terminated.
Note: I don’t see any difference in above conditions 🙂
PGA_AGGREGATE_LIMIT will be set to higher of following values
– 2 GB (default value)
– 200% of the PGA_AGGREGATE_TARGET value
– 3 MB times the value of the PROCESSES parameter.
– Less then 1.2 X RAM – SGA
To simulate this, I did following test using big_table (Code from Asktom)
create table big_table tablespace data_4m as select rownum id, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY from all_objects a where 1=0 / alter table big_table nologging; --Load the table declare l_cnt number; l_rows number := &1; begin insert /*+ append */ into big_table select rownum, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY from all_objects a where rownum <= &1; l_cnt := sql%rowcount; commit; while (l_cnt < l_rows) loop insert /*+ APPEND */ into big_table select rownum+l_cnt, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY from big_table where rownum <= l_rows-l_cnt; l_cnt := l_cnt + sql%rowcount; commit; end loop; end; / --gather stats exec dbms_stats.gather_table_stats ( ownname => 'AMIT',tabname => 'BIG_TABLE' )
Let’s check the size of table
select owner,table_name,num_rows from dba_tables where table_name='BIG_TABLE'; OWNER TABLE_NAME NUM_ROWS -------------------- -------------------- ---------- AMIT BIG_TABLE 110000000
PGA_AGGREGATE_LIMIT is set to 2G (default value). This can’t be lowered as 2G is least value allowed for it
SQL> alter system set pga_aggregate_limit=1g; alter system set pga_aggregate_limit=1g * ERROR at line 1: ORA-02097: parameter cannot be modified because specified value is invalid ORA-00093: pga_aggregate_limit must be between 2048M and 100000G
Before proceeding with this test PGA_AGGREGATE_TARGET was bumped to 30g so that processes can get more PGA memory
Created a shell file with following code
cat 1.sh modname=$1 sqlplus -s amit/amit <<EOF set pages 1000 lines 100 set autot traceonly exec dbms_application_info.set_module(module_name=>'${modname}',action_name=>'') select * from big_table t1,big_table t2 where t1.object_id =t2.object_id; exit EOF
This code is executed via for loop with 20 sessions
for ((i=1;i<=20;i++)) do nohup sh 1.sh PGA_LIMIT${i} & done
In separate session ran following queries
set pages 1000 lines 200 col event for a30 col module for a30 select s.sid,s.serial#,p.spid,p.pga_used_mem/1024/1024 PGA_MB,s.status,s.event,s.module from v$session s ,v$process p where s.paddr=p.addr and s.module like 'PGA_LIMIT%' and wait_class<>'Idle' order by module / select sum(pga_used_mem)/1024/1024 pga_used_mb from v$process;
Output of the query was like this
SQL> @pga SID SERIAL# SPID PGA_MB STATUS EVENT MODULE ---------- ---------- ------------------------ ---------- -------- ------------------------------ ------------------------------ 262 243 20941 130.878675 ACTIVE direct path write temp PGA_LIMIT1 390 77 20957 130.878675 ACTIVE direct path write temp PGA_LIMIT10 154 11 20938 130.816335 ACTIVE direct path write temp PGA_LIMIT11 35 77 20921 130.944379 ACTIVE direct path write temp PGA_LIMIT12 266 35 20906 130.878675 ACTIVE direct path write temp PGA_LIMIT13 141 17 20917 130.878675 ACTIVE direct path write temp PGA_LIMIT14 263 59 20945 130.878675 ACTIVE direct path write temp PGA_LIMIT15 25 55 20943 130.878675 ACTIVE direct path write temp PGA_LIMIT16 135 119 20942 130.878675 ACTIVE direct path write temp PGA_LIMIT17 383 217 20923 130.878675 ACTIVE direct path write temp PGA_LIMIT18 371 391 20937 130.816335 ACTIVE direct path write temp PGA_LIMIT19 382 163 20955 130.878675 ACTIVE direct path write temp PGA_LIMIT2 29 35 20954 130.816335 ACTIVE direct path write temp PGA_LIMIT20 144 103 20947 130.878675 ACTIVE direct path write temp PGA_LIMIT3 136 15 20952 130.878675 ACTIVE direct path write temp PGA_LIMIT4 38 5 20926 130.882039 ACTIVE direct path write temp PGA_LIMIT5 257 139 20902 130.878675 ACTIVE direct path write temp PGA_LIMIT6 260 73 20939 130.816335 ACTIVE direct path write temp PGA_LIMIT7 381 13 20951 130.878675 ACTIVE direct path write temp PGA_LIMIT8 23 101 20915 130.878675 ACTIVE direct path write temp PGA_LIMIT9 20 rows selected. Elapsed: 00:00:00.00 PGA_USED_MB ----------- 2684.47882
Note that this is more then 2G limit and we still didn’t see failures. Reason is that we have set pga_aggregate_target to 30G . Checking parameter value for pga_aggregate_limit still shows 2G but it seems it has risen to higher value (since pga_aggregate_target is 30G now). At this moment, I reduced the pga_aggregate_target to 500m. Immediately some of the db sessions were automatically cleared. Excerpt from alert log
ALTER SYSTEM SET pga_aggregate_target=500M SCOPE=BOTH; 2013-07-07 11:27:34.015000 +00:00 Errors in file /home/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_20923.trc (incident=12476): ORA-04036: PGA memory used by the instance exceeds PGA_AGGREGATE_LIMIT Errors in file /home/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_20939.trc (incident=12433): ORA-04036: PGA memory used by the instance exceeds PGA_AGGREGATE_LIMIT
Checking V$Session confirms same
SID SERIAL# SPID PGA_MB STATUS EVENT MODULE ---------- ---------- ------------------------ ---------- -------- ------------------------------ ------------------------------ 262 243 20941 130.878675 ACTIVE direct path write temp PGA_LIMIT1 390 77 20957 130.878675 ACTIVE direct path write temp PGA_LIMIT10 266 35 20906 130.878675 ACTIVE direct path write temp PGA_LIMIT13 141 17 20917 130.878675 ACTIVE direct path write temp PGA_LIMIT14 25 55 20943 130.878675 ACTIVE direct path write temp PGA_LIMIT16 135 119 20942 130.878675 ACTIVE direct path write temp PGA_LIMIT17 382 163 20955 130.878675 ACTIVE direct path write temp PGA_LIMIT2 144 103 20947 130.878675 ACTIVE direct path write temp PGA_LIMIT3 136 15 20952 130.878675 ACTIVE direct path write temp PGA_LIMIT4 257 139 20902 130.878675 ACTIVE direct path write temp PGA_LIMIT6 381 13 20951 130.878675 ACTIVE direct path write temp PGA_LIMIT8 23 101 20915 130.878675 ACTIVE direct path write temp PGA_LIMIT9 12 rows selected. PGA_USED_MB ----------- 1637.30552
Since limit is set to 2G, it has cleared sessions automatically. login_time is not considered for killing session as we can find PGA_LIMIT7, 11,12 missing from the remaining sessions.
Recent Comments