{"id":448,"date":"2017-10-15T21:29:34","date_gmt":"2017-10-15T19:29:34","guid":{"rendered":"http:\/\/blog.sqlora.com\/en\/?p=448"},"modified":"2018-04-06T13:56:22","modified_gmt":"2018-04-06T11:56:22","slug":"ilm-storage-tiering","status":"publish","type":"post","link":"https:\/\/blog.sqlora.com\/en\/ilm-storage-tiering\/","title":{"rendered":"ILM storage tiering"},"content":{"rendered":"<p>Being not really new term introduced in 12c, Information Lifecycle Management has been enriched with two new features: Heat Map and ADO (Automatic Data Optimization). The letter allows to define policies on data segments (tables, partitions), which consist of conditions and actions. The conditions are generally being checked based on the information gathered with the Heat Map and defined actions are then taken: compress the data (compression tiering) or move the data (storage tiering). I said &#8220;generally&#8221;,  because, on the one hand,  one can define custom conditions (PL\/SQL functions) not necessarily using Heat Map and, on the other hand, because of the rather confusing situation using conditions with storage tiering. <!--more--><\/p>\n<p>In 12.1 the syntax diagram for ILM clause was quite misleading, suggesting that we can define the policy based on conditions. <\/p>\n<p><a href=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1.png\" alt=\"\" width=\"1017\" height=\"286\" class=\"alignnone size-full wp-image-451\" srcset=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1.png 1017w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1-300x84.png 300w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1-768x216.png 768w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_ilm-1-624x175.png 624w\" sizes=\"auto, (max-width: 1017px) 100vw, 1017px\" \/><\/a><\/p>\n<p>Obviously it was a documentation bug, it simply doesn&#8217;t work:<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSCOTT&gt; ALTER TABLE scott.employee\r\n  2  ILM ADD POLICY TIER TO low_cost_store\r\n  3  SEGMENT AFTER 10 DAYS OF NO MODIFICATION;\r\nSEGMENT AFTER 10 DAYS OF NO MODIFICATION\r\n        *\r\nERROR at line 3:\r\nORA-01735: invalid ALTER TABLE option \r\n\r\nSCOTT&gt; ALTER TABLE scott.employee ILM ADD POLICY TIER TO low_cost_store;\r\n\r\nTable altered.\r\n<\/pre>\n<p>Beside of custom conditions using PL\/SQL functions, only the simplest form without condition seems to work. The decision when to start moving segments is based upon tablespace space pressure. ADO parameters <strong>TBS_PERCENT_USED<\/strong>  and <strong>TBS_PERCENT_FREE<\/strong> are there to further control the behavior. <a href=\"http:\/\/www.oracle.com\/technetwork\/database\/automatic-data-optimization-wp-12c-1896120.pdf\" rel=\"noopener\" target=\"_blank\">Oracle&#8217;s White Paper<\/a> states the following:<\/p>\n<p><em>The justification for making storage tiering dependent on &#8220;space pressure&#8221; is exactly as you might imagine, the belief that organizations will want to keep as much data as possible on their high performance (and most expensive) storage tier, and not move data to a lower performance storage tier until it is absolutely required. The exception to the storage pressure requirement are storage tiering policies with the &#8216;READ ONLY&#8217; option, these are triggered by a heat-map based condition clause.<\/em><\/p>\n<p>Personally I cannot completely agree  with this argumentation. Why not also provide other options the same way as for compression? But the second statement made me curious.<\/p>\n<p>&nbsp;<br \/>\nThe 12.2 documentation  offers the corrected version of the syntax diagram for storage tiering (now separated from compression tiering):<\/p>\n<p><a href=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm.png\" alt=\"\" width=\"1134\" height=\"266\" class=\"alignnone size-full wp-image-453\" srcset=\"https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm.png 1134w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm-300x70.png 300w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm-768x180.png 768w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm-1024x240.png 1024w, https:\/\/blog.sqlora.com\/en\/wp-content\/uploads\/sites\/2\/2017\/10\/syntax_new_ilm-624x146.png 624w\" sizes=\"auto, (max-width: 1134px) 100vw, 1134px\" \/><\/a><\/p>\n<p>&nbsp;<br \/>\nAccording to this one it should be possible to define conditions if we move the segments to a read-only tablespace.<br \/>\nDoes it work as described? Let us construct an example based on <a href=\"http:\/\/www.oracle.com\/webfolder\/technetwork\/tutorials\/obe\/db\/12c\/r1\/ilm\/ilm_tiering\/ilm_tiering.html\" rel=\"noopener\" target=\"_blank\">Oracle&#8217;s one<\/a>.<\/p>\n<p>First we create a tablespace to move the table to and set it read-only. Quite important: this tablespace will be set read-write to move data and then again read-only. That is why we need to grant ALTER TALESPACE to SCOTT. <\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSYS&gt; create tablespace low_cost_store\r\n  2  datafile '&amp;_data_path\/lowcoststore01.dbf' size 1M ;\r\n\r\nTablespace created.\r\n\r\nSYS&gt; \r\nSYS&gt; alter tablespace low_cost_store read only;\r\n\r\nTablespace altered.\r\n\r\nSYS&gt; \r\nSYS&gt; grant alter tablespace, select any dictionary to scott;\r\n\r\nGrant succeeded.\r\n\r\nSYS&gt; ---------------------------------------------------------\r\nSYS&gt; -- Table EMPLOYEE is stored in default tablespace USERS\r\nSYS&gt; ---------------------------------------------------------\r\nSYS&gt; SELECT owner, segment_name, tablespace_name\r\n  2    FROM dba_segments\r\n  3   WHERE segment_name = 'EMPLOYEE';\r\n\r\nOWNER\t   SEGMENT_NAME \tTABLESPACE_NAME\r\n---------- -------------------- ------------------------------\r\nSCOTT\t   EMPLOYEE             USERS\r\n\r\n<\/pre>\n<p>&nbsp;<br \/>\nNext we create the policy to move the data after ten days of no modification and verify that in data dictionary. Note that we have ACTION_TYPE=&#8221;STORAGE&#8221; and nevertheless CONDITION_TYPE is set.<br \/>\n&nbsp;<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nSCOTT&gt; -- Storage tiering with condition only to move to read-only tablespace\r\nSCOTT&gt; ALTER TABLE scott.employee\r\n  2  ILM ADD POLICY TIER TO low_cost_store READ ONLY\r\n  3  SEGMENT AFTER 10 DAYS OF NO MODIFICATION;\r\n\r\nTable altered.\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; ----------------------------------------------------------------------------\r\nSCOTT&gt; -- Show ILM policy information\r\nSCOTT&gt; ----------------------------------------------------------------------------\r\nSCOTT&gt; SELECT policy_name, action_type, scope, tier_tablespace, condition_type, condition_days\r\n  2    FROM user_ilmdatamovementpolicies;\r\n\r\nPOLICY_NAME ACTION_TYPE SCOPE\tTIER_TABLESPACE  CONDITION_TYPE         CONDITION_DAYS\r\n----------- ----------- ------- ---------------- ---------------------- --------------\r\nP162\t    STORAGE     SEGMENT LOW_COST_STORE   LAST MODIFICATION TIME \t    10\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; SELECT policy_name, object_name, object_type, enabled\r\n  2    FROM user_ilmobjects;\r\n\r\nPOLICY_NAME OBJECT_NAME \t OBJECT_TYPE\t    ENABLED\r\n----------- -------------------- ------------------ -------\r\nP162\t    EMPLOYEE\t\t TABLE\t\t    YES\r\n \r\n<\/pre>\n<p>&nbsp;<br \/>\nNext we&#8217;ll do this trick with setting the ILM evaluation time to seconds, as shown in Oracle&#8217;s example, flush Heat Map information and wait more than ten seconds:<br \/>\n&nbsp;<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nSYS&gt; -- 1. Switch ILM unit to seconds\r\nSYS&gt; EXECUTE dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.POLICY_TIME, DBMS_ILM_ADMIN.ILM_POLICY_IN_SECONDS);\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSYS&gt; -- 2. set start date\r\nSYS&gt; EXECUTE DBMS_ILM_ADMIN.SET_HEAT_MAP_START(start_date =&gt; sysdate - 50);\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSYS&gt; EXECUTE dbms_ilm.flush_all_segments;\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSYS&gt; EXECUTE  dbms_lock.sleep(15);\r\n\r\nPL\/SQL procedure successfully completed. \r\n\r\n<\/pre>\n<p>&nbsp;<br \/>\nExecute the ILM job manually and see what happened. The table was moved to the new tablespace <em><strong>low_cost_store<\/strong><\/em>. ILM task was executed as expected.<br \/>\n&nbsp;<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; -- Run ILM data movement task\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; declare\r\n  2  v_executionid number;\r\n  3  begin\r\n  4    dbms_ilm.execute_ILM (ILM_SCOPE =&gt; dbms_ilm.SCOPE_SCHEMA,\r\n  5  \t\t execution_mode =&gt; dbms_ilm.ilm_execution_offline,\r\n  6  \t\t task_id   =&gt; v_executionid);\r\n  7  end;\r\n  8  \/\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; -- Table EMPLOYEE is now moved to tablespace LOW_COST_STORE\r\nSCOTT&gt; --------------------------------------------------------------------------------------------------\r\nSCOTT&gt; select tablespace_name, segment_name\r\n  2  from user_segments\r\n  3  where segment_name='EMPLOYEE';\r\n\r\nTABLESPACE_NAME \t       SEGMENT_NAME\r\n------------------------------ --------------------\r\nLOW_COST_STORE\t\t       EMPLOYEE\r\n\r\n1 row selected.\r\n\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; -- Show ILM task results\r\nSCOTT&gt; --------------------------------------------------------------------------------------------------\r\nSCOTT&gt; SELECT task_id, to_char(start_time, 'dd\/mm\/yyyy hh24:mi:ss') as start_time\r\n  2  FROM user_ilmtasks;\r\n\r\n   TASK_ID START_TIME\r\n---------- -------------------\r\n       162 12\/10\/2017 14:50:24\r\n\r\n1 row selected.\r\n\r\nSCOTT&gt; select task_id, job_name, job_state, to_char(completion_time, 'dd\/mm\/yyyy hh24:mi:ss') completion\r\n  2  from user_ilmresults;\r\n\r\n   TASK_ID JOB_NAME\t   JOB_STATE\t\t\t       COMPLETION\r\n---------- --------------- ----------------------------------- ------------------------------\r\n       162 ILMJOB4148\t   COMPLETED SUCCESSFULLY\t       12\/10\/2017 14:50:26\r\n\r\n1 row selected. \r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>I&#8217;ve tested it in 12.1.0.1 &#8211; it works! So obviously this was no enhancement or bugfix in 12.1.0.2 or 12.2.0.1 but simply a documentation bug. And now the documentation is fixed for 12.1 as well!<\/p>\n<div class=\"crp-list-container\"><h3 class=\"crp-list-title\">Related Posts<\/h3><ul class=\"crp-list\"><li class=\"crp-list-item crp-list-item-image-none\"><div class=\"crp-list-item-title\"><a href=\"https:\/\/blog.sqlora.com\/en\/custom-ilm-ado-policy-conditions-using-plsql\/\" target=\"_blank\">Custom ILM ADO policy conditions using PL\/SQL<\/a><\/div><\/li><li class=\"crp-list-item crp-list-item-image-none\"><div class=\"crp-list-item-title\"><a href=\"https:\/\/blog.sqlora.com\/en\/ilm-is-it-possible-to-mix-ado-policies-for-compression-and-storage\/\" target=\"_blank\">ILM - is it possible to mix ADO policies for compression and storage?<\/a><\/div><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Being not really new term introduced in 12c, Information Lifecycle Management has been enriched with two new features: Heat Map and ADO (Automatic Data Optimization). The letter allows to define policies on data segments (tables, partitions), which consist of conditions and actions. The conditions are generally being checked based on the information gathered with the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14,64,2],"tags":[62,59,58,61,60],"class_list":["post-448","post","type-post","status-publish","format-standard","hentry","category-12c","category-ilm","category-oracle","tag-condition","tag-ilm","tag-information-lifecycle-management","tag-policy","tag-storage-tiering"],"_links":{"self":[{"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/posts\/448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/comments?post=448"}],"version-history":[{"count":31,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/posts\/448\/revisions"}],"predecessor-version":[{"id":708,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/posts\/448\/revisions\/708"}],"wp:attachment":[{"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/media?parent=448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/categories?post=448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.sqlora.com\/en\/wp-json\/wp\/v2\/tags?post=448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}