Database Capacity Planning

Capacity and Growth Forecast

How to estimate the growth and forecast of a database on a host.
Step-by-step guide

The procedure is at the bottom of this article.

Login to enterprise manager from sqlplus (from omsdbaup03)
oracle@omsdbaup03:/users/oracle [emrep12c]

$ sqlplus sysman/xxxxxx

2. Follow the following to calculate growth for each database on a host

SQL> set serveroutput on;
SQL> exec db_growth('ITRDBAUP02','text');
Host is ITRDBAUP02
Database: DOVITRHAUP1
Allocated DB free mb 319240.56 MB
Allocated OS free mb 2132379880 MB
Growth per month 247.91 MB
This system will reach 100% by : Too far in the future to calculate
------------------------------------------------------------------------
Host is ITRDBAUP02
Database: DOVITRKAUP1
Allocated DB free mb 281163.5 MB
Allocated OS free mb 2132379880 MB
Growth per month 21420.16 MB
This system will reach 100% by : Too far in the future to calculate
------------------------------------------------------------------------
Disclaimer: This is an estimate only, data is not distributed evenly across all
tablespaces and is not consumed evenly either!

The following parameters are accepted.

procedure: db_growth

Parameter 1: host_name

Parameter 2: output type, (text or excel). Default is excel

Parameter 3: header: on/off (if using excel, it will display a list of headings per column). Default is off

Parameter 4: debug: 0/1 (this will display a list of debugging features for development only). Default is 0 (off)

Here is the procedure:

CREATE OR REPLACE PROCEDURE SYSMAN.db_growth (in_host_name in varchar2, output in varchar2 default 'excel', header in varchar2 default 'off', debugme in number default 0)
IS
/* Who         When          Why
   Mark Young  2-June-2016   Calculate growth and how much time we have left
   Mark Young  2-August-2016    Changed the value of in_host to upper(in_host)
   Mark Young  16-August-2016   If the value return null, output a 0
   Mark Young  18-August-2016   Support for ASM and RAC systems
   Mark Young  19-August-2016   Have 2 methods of output Excel or Text
   Mark Young  24-August-2016	Change the algorithm 
   Mark Young  26-August-2016   alter session set nls_date_format='DD/MM/YYYY';
   Mark Young  28-Nov-2016      Make a simple version Total space left divided by Growth Per Month
*/

        --Declare the variables here
        v_target_guid  		varchar2(255);
		v_host_target_guid 	varchar2(90);
		v_avg_month 		number;
		v_datafile_count	number;	
		v_datafile_1		varchar2(255);
		v_os_free			number;
                v_output_result     number;
                in_host             varchar2(80);
                v_output_null       varchar2(10);
                v_cluster_name      varchar2(50);
                v_cluster_host      varchar2(80); 
                v_is_asm            number;
                V_CLUSTER_TARGET    varchar2(50);
                v_alloc_free_mb     number;
                V_months_left       varchar2(20);
                v_enddate           date;
                v_enddate_mess      varchar2(60);
                v_mymonths_left     varchar2(90);
                v_diskgroup         varchar2(2000);
                v_total_mb          number;
                v_percent_used      number; 
                v_usable_total_mb   number;  
        
		--Get the TARGET_GUID FROM THE HOST
		cursor get_db_targets
		is
		  SELECT DISTINCT a.target_name, a.target_guid, t.target_type, a.host_name
          FROM MGMT$DB_DBNINSTANCEINFO_ALL a, mgmt$target_type t
         WHERE     a.target_guid = t.target_guid
                 AND UPPER(A.HOST_NAME) like upper(substr(in_host_name,0,length(in_host_name)-1) || '%')
                    AND (   t.target_type = 'rac_database'
                    OR (    t.target_type = 'oracle_database'
                        AND t.TYPE_QUALIFIER3 != 'RACINST')) order by 1;
						
	BEGIN
        --Change the session to dd-mm-yyyy
        dbms_session.set_nls('nls_date_format', '''dd-mm-yyyy''');
        dbms_output.enable (1000000); 
         
        --Convert the host to uppercase
        in_host := upper(in_host_name);
		
	--First, lets get the target_guid from the input host name
        SELECT TARGET_GUID into v_host_target_guid FROM MGMT$target WHERE upper(TARGET_NAME)=upper(in_host_name) AND TARGET_TYPE='host';
   
        --generate the header if this is excel
	if header = 'on' then
            dbms_output.put_line(upper('Host ' || chr(9)  || 'Target' || chr(9) || 'DB Growth (per month)'  || chr(9) ||  'OS Free Space'  || chr(9) || 'Average Growth Per Month' || chr(9) || '100% Full' ));
        end if;

		
	FOR i in get_db_targets LOOP  
       
           --Lets see if it's a RAC instance
           if debugme = 1 then
                dbms_output.put_line('Target: ' || upper(i.target_type));
                dbms_output.put_line('Host_target_guid=' || v_host_target_guid);
           end if;
           
           --Now lets open the cursor and get the result for each target on the host.
           SELECT
			   (max(round(avg(a_size.size_gb*1024),2)) - min(round(avg(a_size.size_gb*1024),2)))/13 into v_avg_month
			 FROM
			  (SELECT  
				   m.rollup_timestamp AS month_timestamp,
				   sum(m.average/1024) AS size_gb
				 FROM 
				   mgmt$metric_daily m,
				   mgmt$target_type t
				 WHERE 
				   t.target_guid=HEXTORAW(i.target_guid) AND
				   (t.target_type='rac_database' OR 
				   (t.target_type='oracle_database' AND t.TYPE_QUALIFIER3 != 'RACINST')) AND      
				   m.target_guid=t.target_guid AND
				   m.metric_guid=t.metric_guid AND
				   t.metric_name='tbspAllocation' AND
				   (t.metric_column='spaceAllocated') AND
				   m.rollup_timestamp >= sysdate-365 AND
				   m.rollup_timestamp <= sysdate GROUP BY m.metric_column, m.rollup_timestamp) a_size, (SELECT m.rollup_timestamp AS month_timestamp, sum(m.average/1024) AS used_gb FROM mgmt$metric_daily m, mgmt$target_type t WHERE t.target_guid=HEXTORAW(i.target_guid) AND (t.target_type='rac_database' OR (t.target_type='oracle_database' AND t.TYPE_QUALIFIER3 != 'RACINST')) AND m.target_guid=t.target_guid AND m.metric_guid=t.metric_guid AND t.metric_name='tbspAllocation' AND (t.metric_column='spaceUsed') AND m.rollup_timestamp >= sysdate-365 AND
				   m.rollup_timestamp <= sysdate GROUP BY m.metric_column, m.rollup_timestamp) used WHERE a_size.month_timestamp =used.month_timestamp GROUP BY TO_CHAR(a_size.month_timestamp,'MON RR'); -- if output='text' then --dbms_output.put_line(upper('Host: ' || i.host_name)); -- dbms_output.put_line('Growth per month: ' || trunc(v_avg_month,2) || ' MB'); -- end if; --If the database is ASM then we need to do some other magic. -- select count(*) into v_is_asm from mgmt$target where upper(host_name)=in_host and (type_qualifier2='ASM' or type_qualifier2='ASMINST'); select count(*) into v_is_asm from sysman.CM$MGMT_ASM_INSTANCE_ECM where upper(host_name)=in_host; if debugme=1 then dbms_output.put_line('is this asm: ' || v_is_asm); end if; SELECT --to_char(trunc(SUM(t.tablespace_size/1024/1024), 2),'999,999,999,999') AS ALLOC_MB, -- to_char(trunc(SUM(t.tablespace_used_size/1024/1024), 2),'999,999,999,999') AS USED_MB, trunc(SUM((t.tablespace_size - tablespace_used_size)/1024/1024), 2) into v_alloc_free_mb FROM mgmt$db_tablespaces t, (SELECT target_guid FROM mgmt$target WHERE target_guid=HEXTORAW(i.target_guid) AND (target_type='rac_database' OR (target_type='oracle_database' AND TYPE_QUALIFIER3 != 'RACINST'))) tg WHERE t.target_guid=tg.target_guid; if v_is_asm > 0 then
            --Get the cluster nanme
            dbms_output.put_line ('in host is ' || in_host );
            
            select lower(cluster_name) into V_CLUSTER_TARGET from sysman.MGMT_CLUSTER_CONFIG where upper(node_list) like '%' || in_host || '%';
            
            --Get the diskgroup from the datafiles in the DB
            select RTRIM(XMLAGG(XMLELEMENT(e,diskgroup || ',')).EXTRACT('//text()'),',') diskgroup into v_diskgroup from 
            (SELECT DISTINCT DISKGROUP FROM MGMT_ASM_CLIENT_ECM where upper(db_name) like SUBSTR(i.target_name,0,8) || '%' and UPPER(diskgroup) not like '%FRA%');
            
            DBMS_OUTPUT.PUT_LINE('Diskgroup: ' || v_diskgroup);
            dbms_output.put_line('Cluster name: +ASM_' || v_cluster_target);
            dbms_output.put_line('Target name: ' || i.target_name);
            
                      --this is for calculating the ASM usage
                      SELECT 
                             MAX (DECODE (seq, 1, CEIL (VALUE))),    
                             MAX (DECODE (seq, 3, CEIL (VALUE))),    
                             MAX (DECODE (seq, 2, CEIL (VALUE))),         -- PERCENT_USED
                             MAX (DECODE (seq, 4, CEIL (VALUE)))     -- USABLE_TOTAL_MB
                             into v_os_free,
                             v_total_mb,
                             v_percent_used, 
                             v_usable_total_mb  
                        FROM (SELECT target_name,
                                     key_value diskgroup,
                                     VALUE,
                                     metric_column,
                                     ROW_NUMBER ()
                                     OVER (PARTITION BY target_name, key_value
                                           ORDER BY metric_column)
                                        seq
                                FROM mgmt$metric_current
                               WHERE     lower(target_name) = '+asm_' || V_CLUSTER_TARGET
                                     AND key_value in (SELECT DISTINCT DISKGROUP FROM sysman.MGMT_ASM_CLIENT_ECM where upper(db_name) like SUBSTR(i.target_name,0,8) || '%' and UPPER(diskgroup) not like '%FRA%')
                                     AND metric_name = 'DiskGroup_Usage'
                                     AND metric_column IN ('total_mb',
                                                           'free_mb',
                                                           'percent_used',
                                                           'usable_total_mb'));
                                                           
                                                           dbms_output.put_line('os_free: ' || v_os_free);
                                                           

        else
              
            --Now calculate free space in the OS, but only use the mountpoint allocated to the database.
            SELECT --mountpoint,
                   --TRUNC (sizeb / 1024 / 1024, 2)                                  "TOTAL",
                   --TRUNC (USEDB / 1024 / 1024, 2)                                  "USED",
                   sum(TRUNC(FREEB/ 1024/1024, 2)) into v_os_free                                 
                   --TRUNC ( (USEDB / 1024 / 1024) / (sizeb / 1024 / 1024) * 100, 2) "%"
              FROM mgmt$storage_report_localfs
             WHERE     UPPER (target_name) = (in_host)
                   AND mountpoint IN
                          (SELECT DISTINCT os_storage_entity
                             FROM mgmt$DB_DATAFILES
                            WHERE     upper (HOST_name) = in_host
                                  AND upper(target_name) = upper(i.target_name)); 
            

          end if;	
            
            if (v_avg_month > 0)  then
                select trunc(((v_alloc_free_mb + v_os_free)/v_avg_month),2) into v_months_left from dual;
                dbms_output.put_line (' Months: ' || v_months_left);
                
                
                if length(v_months_left) < 6 then select add_months(trunc(sysdate),v_months_left) into v_enddate from dual; v_enddate_mess := v_enddate; else if output='text' then v_enddate_mess := 'Too far in the future to calculate'; else v_enddate_mess := 'N/A'; end if; end if; if output='text' then v_mymonths_left := 'This system will reach 100% by : ' || v_enddate_mess; else v_mymonths_left := v_enddate_mess; end if; else v_mymonths_left := 'N/A'; end if; if output = 'text' then dbms_output.put_line('Host is ' || in_host); dbms_output.put_line('Database: ' || i.target_name); dbms_output.put_line('Allocated DB free mb ' || v_alloc_free_mb || ' MB'); if v_is_asm > 0 then
                        dbms_output.put_line('Allocated Diskgroup free ' || v_diskgroup || ' ' || v_os_free || ' MB');
                        dbms_output.put_line('Total MB free ' || v_diskgroup || ' ' || v_total_mb || ' MB');
                        dbms_output.put_line('Percentage free ' || v_diskgroup || ' ' || v_percent_used || '%'); 
                        dbms_output.put_line('Total Usable ' || v_diskgroup || ' ' || v_usable_total_mb || ' MB');
                    else
                        dbms_output.put_line('Allocated OS free mb ' || v_os_free || ' MB');    
                    end if;
                 
                    dbms_output.put_line('Growth per month ' || trunc(v_avg_month,2) || ' MB');
                    dbms_output.put_line (v_mymonths_left);
                    dbms_output.put_line ('------------------------------------------------------------------------');
            else
               
                    dbms_output.put_line(i.host_name || chr(9) || i.target_name || chr(9) || v_alloc_free_mb || chr(9) || v_os_free || chr(9) || trunc(v_avg_month,2) || chr(9) || v_enddate_mess);
            end if;  

 
        END LOOP;
        dbms_output.put_line ('Disclaimer: This is an estimate only, data is not distributed evenly across all tablespaces and is not consumed evenly either!');
end;
/

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.