GOAL
This article shows an example for applying ILM ADO storage tiering policy on table partition.
SOLUTION
The example creates and enforces ADO storage tiering policy on the partition JAN_1_2007 of the ILM_DEMO table.
The policy is created by the following command:
ALTER TABLE ILM_DEMO MODIFY PARTITION JAN_1_2007 ILM ADD POLICY TIER TO ILMTSDEMO_LOWCOST;
The example shows that the partition JAN_1_2007 is originally stored on ILM_SOURCE tablespace.
After data load into partition JAN_1_2007, the ILM_SOURCE tablespace got 75% full, 25% free.
We added a storage tiering policy to partition JAN_1_2007 to move it to ILMTSDEMO_LOWCOST tablespace.
The policy evaluates to true when the tablespace containing the object meets the tablespace fullness threshold.
The example shows that this did not happen initally and dba_ilmevaluationdetails show PRECONDITION NOT SATISFIED after policy evaluation.
In order to the policy to evaluate to true we adjusted the ILM parameters TBS_PERCENT_FREE and TBS_PERCENT_USED, then the policy evaluated to true and the corresponding ILM job was triggered to carry out the move of the JAN_1_2007 partition to the ILMTSDEMO_LOWCOST tablespace.
After the ILM job completed, the corresponding storage tiering policy was disabled automatically.
Througout the example we forced the evaluation of the policy instead of waiting for the maintenance window to open and trigger the policy evaluation and the corresponding job (as by default ILM policies are evaluated in the maintenance window).
The example script is the following.
You may need to execute the dbms_ilm_admin procedures as SYS AS SYSDBA user in order to avoid ORA-38330: insufficient privilege for ILM operation. This is due to bug 16887946, which is fixed in 12.2.
For simplicity the example below has been executed as user SYS AS SYSDBA in 12.1.0.2.
spool tier_part_ex1.log
set lines 300
set echo on
col name format a30
col policy_name format a11;
col object_owner format a10;
col object_name format a20;
col object_type format a20;
col subobject_name format a23;
col enabled format a7;
col tier_tablespace format a20;
col tier_status format a20;
col custom_function format a20 wrapped;
col TABLE_NAME format a20
col PARTITION_NAME format a25
col "Last Analyzed" format a20
col high_value format a40
col segment_name format a30
col comments format a30
col START_TIME format a30
col COMPLETION_TIME format a30
col STATISTICS format a30
col JOB_NAME format a20
col task_owner format a20
set serveroutput on
alter session set nls_date_format='DD-MM-YYYY HH24:MI:SS';
-- Pre-requisites
-- conn sys as sysdba
-- heat_map = ON
alter system set heat_map = ON;
CREATE TABLESPACE ILM_SOURCE DATAFILE 'ILM_SOURCE.dbf' SIZE 12m REUSE AUTOEXTEND ON NEXT 2m MAXSIZE 1024M EXTENT MANAGEMENT LOCAL;
CREATE TABLESPACE ILMTSDEMO_LOWCOST DATAFILE 'ILMTSDEMO_LOWCOST.dbf' SIZE 50m REUSE AUTOEXTEND ON NEXT 5m MAXSIZE 1024M EXTENT MANAGEMENT LOCAL;
-- Create table and partition JAN_1_2007 in the ILM_SOURCE tablspace and load rows into it
CREATE TABLE ILM_DEMO
(
ILM_TRD_EFF_DT DATE NOT NULL,
ILM_ADT_TIMESTAMP TIMESTAMP(6) DEFAULT (SYSDATE) NOT NULL,
ILM_BIN_NO VARCHAR2(20 BYTE) DEFAULT ' ' NOT NULL,
ILM_NETWRK_LEVEL VARCHAR2(2 BYTE) DEFAULT ' ' NOT NULL
)
PARTITION BY RANGE (ILM_TRD_EFF_DT)
(
PARTITION JAN_1_2007 VALUES LESS THAN (TO_DATE(' 2007-01-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOCOMPRESS TABLESPACE ILM_SOURCE,
PARTITION ILM_DEMO_PART_20140430 VALUES LESS THAN (TO_DATE(' 2014-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOCOMPRESS ,
PARTITION ILM_DEMO_PART_20140515 VALUES LESS THAN (TO_DATE(' 2014-05-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOCOMPRESS
);
-- Insert rows into partition JAN_1_2007
begin
FOR j in 1..80000 LOOP
insert into ILM_DEMO (ILM_TRD_EFF_DT) values (TO_DATE(' 2007-01-10 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')+1/j);
end loop;
commit;
end;
/
-- Collects stats on the table, so that user_tab_partitions return accurate values
begin DBMS_STATS.GATHER_TABLE_STATS(ownname => user, tabname => 'ILM_DEMO', granularity => 'ALL', cascade => DBMS_STATS.AUTO_CASCADE, method_opt => 'FOR ALL COLUMNS SIZE AUTO', estimate_percent => NULL);
end;
select table_name , PARTITION_NAME , TABLESPACE_NAME , to_char(LAST_ANALYZED,'MM/DD/YYYY HH24:MI') as "Last Analyzed" , NUM_ROWS , BLOCKS from user_tab_partitions where table_name='ILM_DEMO' order by table_name ,partition_position;
select table_name , TABLESPACE_NAME , to_char(LAST_ANALYZED,'MM/DD/YYYY HH24:MI') as "Last Analyzed" , NUM_ROWS , BLOCKS
from user_tables where table_name='ILM_DEMO' order by table_name ;
select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
-- Query space in the ILM_SOURCE tablespace
-- Note % Free and % Used values.
-- We will come back to this later at the storage tiering policy
SELECT /* + RULE */ df.tablespace_name "Tablespace",
df.bytes / (1024 * 1024) "Size (MB)",
SUM(fs.bytes) / (1024 * 1024) "Free (MB)",
Nvl(Round(SUM(fs.bytes) * 100 / df.bytes),1) "% Free",
Round((df.bytes - SUM(fs.bytes)) * 100 / df.bytes) "% Used"
FROM dba_free_space fs,
(SELECT tablespace_name,SUM(bytes) bytes
FROM dba_data_files
GROUP BY tablespace_name) df
WHERE fs.tablespace_name (+) = df.tablespace_name and df.tablespace_name ='ILM_SOURCE'
GROUP BY df.tablespace_name,df.bytes
Order by 4;
-- Create a storage tiering policy on PARTITION JAN_1_2007
-- Note the decision to move segment depends on the default thresholds (see dba_ilmparameters for current values).
ALTER TABLE ILM_DEMO MODIFY PARTITION JAN_1_2007 ILM ADD POLICY TIER TO ILMTSDEMO_LOWCOST;
--info on policy
select * from dba_ilmparameters;
select * from user_ILMDATAMOVEMENTPOLICIES;
select * from user_ilmobjects;
select * from user_ilmpolicies;
-- Force evaluation of the policy, and execution of ADO task
-- for this demo we cannot wait for the maintenance window to open and trigger the ADO policies jobs.
-- Instead, we are going to use the following PL/SQL block and trigger it.
DECLARE
v_executionid number;
BEGIN
dbms_ilm.execute_ILM (ILM_SCOPE => dbms_ilm.SCOPE_SCHEMA,
execution_mode => dbms_ilm.ilm_execution_offline,
task_id => v_executionid);
END;
/
-- shows that the partition has NOT moved to ILMTSDEMO_LOWCOST tablespace
select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
--shows ILM task, and that corresponding job has not been created
-- because during policy evaluation PRECONDITION NOT SATISFIED
select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
-- Adjust TBS_PERCENT_FREE, TBS_PERCENT_USED if you need to in order to get the evaluation of the policy to true,
-- and get the corresponding storage tiering job triggered.
-- You may need to execute these as SYS AS DBA user due to Bug 16887946
-- Tablespace usage threshold paramters in storage tiering
begin dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.TBS_PERCENT_FREE,30);
dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.TBS_PERCENT_USED,70);
end;
select * from dba_ilmparameters;
-- Force evaluation of the policy, and execution of ADO task
DECLARE
v_executionid number;
BEGIN
dbms_ilm.execute_ILM (ILM_SCOPE => dbms_ilm.SCOPE_SCHEMA,
execution_mode => dbms_ilm.ilm_execution_offline,
task_id => v_executionid);
END;
/
--shows ILM task, corresponding job, and its completion status
select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
-- wait for 20 seconds until job completes
EXEC dbms_lock.sleep(20);
select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
-- shows that the partition has moved to ILMTSDEMO_LOWCOST tablespace
select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
-- A segment level tiering policy is disabled after its first execution.
select * from user_ILMDATAMOVEMENTPOLICIES;
select * from user_ilmobjects;
spool off
An output of the above is the following:
SQL> -- Pre-requisites
SQL> -- conn sys as sysdba
SQL>
SQL> -- heat_map = ON
SQL> alter system set heat_map = ON;
System altered.
SQL>
SQL> CREATE TABLESPACE ILM_SOURCE DATAFILE 'ILM_SOURCE.dbf' SIZE 12m REUSE AUTOEXTEND ON NEXT 2m MAXSIZE 1024M EXTENT MANAGEMENT LOCAL;
Tablespace created.
SQL> CREATE TABLESPACE ILMTSDEMO_LOWCOST DATAFILE 'ILMTSDEMO_LOWCOST.dbf' SIZE 50m REUSE AUTOEXTEND ON NEXT 5m MAXSIZE 1024M EXTENT MANAGEMENT LOCAL;
Tablespace created.
SQL>
SQL>
SQL> -- Create table and partition JAN_1_2007 in the ILM_SOURCE tablspace and load rows into it
SQL> CREATE TABLE ILM_DEMO
2 (
3 ILM_TRD_EFF_DT DATE NOT NULL,
4 ILM_ADT_TIMESTAMP TIMESTAMP(6) DEFAULT (SYSDATE) NOT NULL,
5 ILM_BIN_NO VARCHAR2(20 BYTE) DEFAULT ' ' NOT NULL,
6 ILM_NETWRK_LEVEL VARCHAR2(2 BYTE) DEFAULT ' ' NOT NULL
7 )
8 PARTITION BY RANGE (ILM_TRD_EFF_DT)
9 (
10 PARTITION JAN_1_2007 VALUES LESS THAN (TO_DATE(' 2007-01-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
11 NOCOMPRESS TABLESPACE ILM_SOURCE,
12 PARTITION ILM_DEMO_PART_20140430 VALUES LESS THAN (TO_DATE(' 2014-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
13 NOCOMPRESS ,
14 PARTITION ILM_DEMO_PART_20140515 VALUES LESS THAN (TO_DATE(' 2014-05-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
15 NOCOMPRESS
16 );
Table created.
SQL>
SQL> -- Insert rows into partition JAN_1_2007
SQL> begin
2 FOR j in 1..80000 LOOP
3 insert into ILM_DEMO (ILM_TRD_EFF_DT) values (TO_DATE(' 2007-01-10 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')+1/j);
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL>
SQL> -- Collects stats on the table, so that user_tab_partitions return accurate values
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(ownname => user, tabname => 'ILM_DEMO', granularity => 'ALL', cascade => DBMS_STATS.AUTO_CASCADE, method_opt => 'FOR ALL COLUMNS SIZE AUTO', estimate_percent => NULL);
PL/SQL procedure successfully completed.
SQL>
SQL> select table_name , PARTITION_NAME , TABLESPACE_NAME , to_char(LAST_ANALYZED,'MM/DD/YYYY HH24:MI') as "Last Analyzed" , NUM_ROWS , BLOCKS from user_tab_partitions where table_name='ILM_DEMO' order by table_name ,partition_position;
TABLE_NAME PARTITION_NAME TABLESPACE_NAME Last Analyzed NUM_ROWS BLOCKS
ILM_DEMO JAN_1_2007 ILM_SOURCE 01/31/2015 12:59 80000 1006
ILM_DEMO ILM_DEMO_PART_20140430 SYSTEM 01/31/2015 12:59 0 0
ILM_DEMO ILM_DEMO_PART_20140515 SYSTEM 01/31/2015 12:59 0 0
SQL>
SQL> select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
TABLESPACE_NAME SEGMENT_NAME SEGMENT_TYPE PARTITION_NAME
ILM_SOURCE ILM_DEMO TABLE PARTITION JAN_1_2007
SQL>
SQL> -- Query space in the ILM_SOURCE tablespace
SQL> -- Note % Free and % Used values.
SQL> -- We will come back to this later at the storage tiering policy
SQL>
SQL> SELECT /* + RULE */ df.tablespace_name "Tablespace",
2 df.bytes / (1024 * 1024) "Size (MB)",
3 SUM(fs.bytes) / (1024 * 1024) "Free (MB)",
4 Nvl(Round(SUM(fs.bytes) * 100 / df.bytes),1) "% Free",
5 Round((df.bytes - SUM(fs.bytes)) * 100 / df.bytes) "% Used"
6 FROM dba_free_space fs,
7 (SELECT tablespace_name,SUM(bytes) bytes
8 FROM dba_data_files
9 GROUP BY tablespace_name) df
10 WHERE fs.tablespace_name (+) = df.tablespace_name and df.tablespace_name ='ILM_SOURCE'
11 GROUP BY df.tablespace_name,df.bytes
12 Order by 4;
Tablespace Size (MB) Free (MB) % Free % Used
ILM_SOURCE 12 3 25 75
SQL>
SQL>
SQL> -- Create a storage tiering policy on PARTITION JAN_1_2007
SQL> -- Note the decision to move segment depends on the default thresholds (see dba_ilmparameters for current values).
SQL>
SQL> ALTER TABLE ILM_DEMO MODIFY PARTITION JAN_1_2007 ILM ADD POLICY TIER TO ILMTSDEMO_LOWCOST;
Table altered.
SQL>
SQL> --info on policy
SQL> select * from dba_ilmparameters;
NAME VALUE
ENABLED 1
RETENTION TIME 30
JOB LIMIT 2
EXECUTION MODE 2
EXECUTION INTERVAL 15
TBS PERCENT USED 85
TBS PERCENT FREE 25
POLICY TIME 0
8 rows selected.
SQL> select * from user_ILMDATAMOVEMENTPOLICIES;
POLICY_NAME ACTION_TYPE SCOPE COMPRESSION_LEVEL TIER_TABLESPACE TIER_STATUS CONDITION_TYPE CONDITION_DAYS CUSTOM_FUNCTION
P382 STORAGE SEGMENT ILMTSDEMO_LOWCOST 0
SQL> select * from user_ilmobjects;
POLICY_NAME OBJECT_OWN OBJECT_NAME SUBOBJECT_NAME OBJECT_TYPE INHERITED_FROM ENABLED DEL
P382 SYS ILM_DEMO JAN_1_2007 TABLE PARTITION POLICY NOT INHERITED YES NO
SQL> select * from user_ilmpolicies;
POLICY_NAME POLICY_TYPE TABLESPACE ENABLED DELETED
P382 DATA MOVEMENT YES NO
SQL>
SQL> -- Force evaluation of the policy, and execution of ADO task
SQL> -- for this demo we cannot wait for the maintenance window to open and trigger the ADO policies jobs.
SQL> -- Instead, we are going to use the following PL/SQL block and trigger it.
SQL> DECLARE
2 v_executionid number;
3 BEGIN
4 dbms_ilm.execute_ILM (ILM_SCOPE => dbms_ilm.SCOPE_SCHEMA,
5 execution_mode => dbms_ilm.ilm_execution_offline,
6 task_id => v_executionid);
7 END;
8 /
PL/SQL procedure successfully completed.
SQL>
SQL> -- shows that the partition has NOT moved to ILMTSDEMO_LOWCOST tablespace
SQL> select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
TABLESPACE_NAME SEGMENT_NAME SEGMENT_TYPE PARTITION_NAME
ILM_SOURCE ILM_DEMO TABLE PARTITION JAN_1_2007
SQL>
SQL> --shows ILM task, and that corresponding job has not been created
SQL> -- because during policy evaluation PRECONDITION NOT SATISFIED
SQL> select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
2 ,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
3 from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
4 where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
TASK_ID TASK_OWNER STATE POLICY_NAME OBJECT_OWN OBJECT_NAME SELECTED_FOR_EXECUTION JOB_NAME JOB_STATE START_TIME COMPLETION_TIME STATISTICS
483 SYS COMPLETED P382 SYS ILM_DEMO PRECONDITION NOT SATISFIED
SQL>
SQL>
SQL> -- Adjust TBS_PERCENT_FREE, TBS_PERCENT_USED if you need to in order to get the evaluation of the policy to true,
SQL> -- and get the corresponding storage tiering job triggered.
SQL> -- You may need to execute these as SYS AS DBA user due to Bug 16887946
SQL> -- Tablespace usage threshold paramters in storage tiering
SQL> EXEC dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.TBS_PERCENT_FREE,30);
PL/SQL procedure successfully completed.
SQL> EXEC dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.TBS_PERCENT_USED,70);
PL/SQL procedure successfully completed.
SQL>
SQL> select * from dba_ilmparameters;
NAME VALUE
ENABLED 1
RETENTION TIME 30
JOB LIMIT 2
EXECUTION MODE 2
EXECUTION INTERVAL 15
TBS PERCENT USED 70
TBS PERCENT FREE 30
POLICY TIME 0
8 rows selected.
SQL>
SQL> -- Force evaluation of the policy, and execution of ADO task
SQL> DECLARE
2 v_executionid number;
3 BEGIN
4 dbms_ilm.execute_ILM (ILM_SCOPE => dbms_ilm.SCOPE_SCHEMA,
5 execution_mode => dbms_ilm.ilm_execution_offline,
6 task_id => v_executionid);
7 END;
8 /
PL/SQL procedure successfully completed.
SQL>
SQL> --shows ILM task, corresponding job, and its completion status
SQL> select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
2 ,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
3 from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
4 where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
TASK_ID TASK_OWNER STATE POLICY_NAME OBJECT_OWN OBJECT_NAME SELECTED_FOR_EXECUTION JOB_NAME JOB_STATE START_TIME COMPLETION_TIME STATISTICS
484 SYS ACTIVE P382 SYS ILM_DEMO SELECTED FOR EXECUTION ILMJOB17892 JOB CREATED
483 SYS COMPLETED P382 SYS ILM_DEMO PRECONDITION NOT SATISFIED
SQL>
SQL> -- wait for 20 seconds until job completes
SQL> EXEC dbms_lock.sleep(20);
PL/SQL procedure successfully completed.
SQL>
SQL> select t.task_id, t.task_owner, t.state,e.policy_name, e.object_owner, e.object_name,e.SELECTED_FOR_EXECUTION
2 ,r.job_name,r.job_state,r.start_time,r.completion_time,r.statistics
3 from dba_ilmtasks t,dba_ilmevaluationdetails e,dba_ilmresults r
4 where t.task_id=e.task_id(+) and t.task_id=r.task_id(+) and e.object_owner = user;
TASK_ID TASK_OWNER STATE POLICY_NAME OBJECT_OWN OBJECT_NAME SELECTED_FOR_EXECUTION JOB_NAME JOB_STATE START_TIME COMPLETION_TIME STATISTICS
484 SYS COMPLETED P382 SYS ILM_DEMO SELECTED FOR EXECUTION ILMJOB17892 COMPLETED SUCCESSFULLY 31-JAN-15 12.59.54.965415 PM 31-JAN-15 12.59.55.064624 PM
483 SYS COMPLETED P382 SYS ILM_DEMO PRECONDITION NOT SATISFIED
SQL>
SQL> -- shows that the partition has moved to ILMTSDEMO_LOWCOST tablespace
SQL> select tablespace_name, segment_name, segment_type,partition_name from user_segments where partition_name='JAN_1_2007';
TABLESPACE_NAME SEGMENT_NAME SEGMENT_TYPE PARTITION_NAME
ILMTSDEMO_LOWCOST ILM_DEMO TABLE PARTITION JAN_1_2007
SQL>
SQL> -- A segment level tiering policy is disabled after its first execution.
SQL> select * from user_ILMDATAMOVEMENTPOLICIES;
POLICY_NAME ACTION_TYPE SCOPE COMPRESSION_LEVEL TIER_TABLESPACE TIER_STATUS CONDITION_TYPE CONDITION_DAYS CUSTOM_FUNCTION
P382 STORAGE SEGMENT ILMTSDEMO_LOWCOST 0
SQL> select * from user_ilmobjects;
POLICY_NAME OBJECT_OWN OBJECT_NAME SUBOBJECT_NAME OBJECT_TYPE INHERITED_FROM ENABLED DEL
P382 SYS ILM_DEMO JAN_1_2007 TABLE PARTITION POLICY NOT INHERITED NO NO
SQL>
SQL> spool off
Next step:
Check out Note 1967038.1 Example for ILM ADO Storage Tiering Policy Using Custom PL/SQL Policy Function on Table Partition