Who moved my cheese parameter?

On databases with multiple DBAs and a not too rigorous change control policy, database parameters get changed and it’s not always clear who made the change and when. Parameter changes are recorded in the instance alert log, but you might not save the alert log that far back. Auditing can tell you what user changed the parameter and when, but what if you don’t have auditing in place and you don’t keep your alert logs around very long?

How about use the AWR? Though the default retention is 8 days in one hour intervals, many databases have a much longer retention and snapshots are done more frequently too — I often see over a year of retention with snapshots every 15 minutes. If that’s the case, you can easily mine DBA_HIST_PARAMETER and at least narrow down when a given parameter was changed, in what PDB it was changed, and in what instance.


There are a couple of catches, though, and the query I’m using to mine that view should take those into account. Here is what DBA_HIST_PARAMETER looks like:

Name            Null?    Type          
--------------- -------- ------------- 
SNAP_ID         NOT NULL NUMBER        
DBID            NOT NULL NUMBER        
VALUE                    VARCHAR2(512) 
ISDEFAULT                VARCHAR2(9)   
ISMODIFIED               VARCHAR2(10)  
CON_DBID                 NUMBER        
CON_ID                   NUMBER      

Notice the columns for CON_ID and INSTANCE_NUMBER. You might change a parameter at the CDB level, and all PDBs will inherit it unless it’s modifiable at the PDB level and it was changed only for that PDB. Also, in a RAC environment you may change a parameter just for one instance for a specific container.

Finally, hidden parameters (that start with an underscore) are not going to be in this view unless they were set or changed for one or more containers.

Here are the requirements for this query:

  • Show the begin and end time range in which a specified parameter was changed
  • Prompt for the following values:
    • parameter name pattern (as part of LIKE)
    • begin date of interest
    • end date of interest
  • Show all attributes of the parameter change for any one of these conditions:
    • A non-hidden or hidden parameter’s value was changed during the time range
    • A hidden parameter’s value was first set during the time range
    • A hidden or non-hidden parameter was set for just one instance in a RAC environment

Parameter change scenarios

Here are some examples where I make changes to various parameters in a RAC environment for two different PDBs. Here is the query:

select parameter_name, pa.instance_number, instance_name,
   cont_id, nvl(name,'CDB$ROOT') cont_name,
   value, old_value, pa.snap_id,
   to_char(begin_interval_time,'YYYY-MM-DD HH24:MI:SS') begin_int, 
   to_char(end_interval_time,'YYYY-MM-DD HH24:MI:SS') end_int
    select snap_id,parameter_name,instance_number,con_id cont_id,value,
       lag(value,1,'FIRST CHANGE')
          over (partition by parameter_name,dbid,instance_number,con_id
                order by snap_id,parameter_name,dbid,instance_number,con_id)
    from dba_hist_parameter
) pa
join dba_hist_snapshot dhs
   on dhs.snap_id = pa.snap_id 
      and dhs.instance_number = pa.instance_number 
      and dhs.con_id=0
join gv$instance i
   on i.instance_number = dhs.instance_number
left join gv$pdbs p
   on p.inst_id = i.instance_number and p.con_id = pa.cont_id
where (value != old_value or old_value = 'FIRST CHANGE')
  and parameter_name like '%&par_name%'
  and begin_interval_time 
     between to_date('&start_dt','YYYY-MM-DD HH24:MI_SS') 
         and to_date('&end_dt','YYYY-MM-DD HH24:MI_SS')
order by instance_number;

The key to the query is the LAG analytic function which facilitates the comparison of adjacent sorted rows in DBA_HIST_PARAMETER to know when a particular parameter’s value has changed within the snapshot. If the parameter was set for the first time within the snapshot, I’ll know that by a previous value of “FIRST CHANGE” assigned in the LAG function itself.

In the first test case, I changed the parameter UNDO_RETENTION from 900 to 1000 on 9/1/2020 at 6:55 P.M. in the root, and by default, all three instances:

-------------------- --------------- ------------- -------- ------------ ---------     --------- -------- ------------------- -------------------
undo_retention                     1 xqa19c1              0 CDB$ROOT     1000          900          23912 2020-09-01 18:45:20 2020-09-01 19:00:06
undo_retention                     2 xqa19c2              0 CDB$ROOT     1000          900          23912 2020-09-01 18:45:20 2020-09-01 19:00:06
undo_retention                     3 xqa19c3              0 CDB$ROOT     1000          900          23912 2020-09-01 18:45:20 2020-09-01 19:00:06

As long as I know a general time range for the parameter change and the parameter itself, I will find it. In this example, I changed the parameter PGA_AGGREGATE_LIMIT to 31G (from 32G) on the PDB REL_CAND and only on instance 2 at 2:35 P.M. on 8/7/2020:

-------------------- --------------- ------------- -------- ------------ -----------   ------------ -------- ------------------- -------------------
pga_aggregate_limit                2 xqa19c2              9 REL_CAND     32505856000   FIRST CHANGE    21495 2020-08-07 14:30:11 2020-08-07 14:45:01

Since that parameter had never been set, the OLD_VALUE is NULL, which I map to “FIRST CHANGE” in the LAG function. The more often you create AWR snapshots the closer you can narrow down when the parameter was changed.

and Exadata!

The need for this view first came up during an Exadata performance investigation — while I could have run a series of AWR compare reports to see what parameters changed (DBA_HIST_PARAMETER is one of the sources for an AWR compare report), using this query is much more straightforward. The offloading performance of the Exadata system in question returned to normal after a series of performance issues, so I suspected that some cell layer parameters were to blame. I ran the query for any parameters containing the word “cell” and found the culprit at the beginning of May:

----------------------- --------------- ------------- -------- ------------ --------- ---------- -------- ------------------- -------------------
cell_offload_processing               1 PRDCDB1              0 CDB$ROOT     TRUE      FALSE         14243 2020-05-01 23:00:15 2020-05-02 00:00:26

cell_offload_processing               2 PRDCDB2              0 CDB$ROOT     TRUE      FALSE         14243 2020-05-01 23:00:15 2020-05-02 00:00:26

The parameter CELL_OFFLOAD_PROCESSING had been set back to TRUE right before midnight on 5/1/2020, and performance went back to normal. When it was set to FALSE is unknown, since the AWR snapshots were not retained before April.


Unless you create unique users for all of your DBAs and turn on auditing for ALTER SYSTEM, you won’t know who made a change to a parameter in which container, but at least you’ll know approximately when it was changed!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s