{"id":357,"date":"2017-10-24T21:02:19","date_gmt":"2017-10-24T19:02:19","guid":{"rendered":"http:\/\/blog.sqlora.com\/de\/?p=357"},"modified":"2018-04-06T13:55:34","modified_gmt":"2018-04-06T11:55:34","slug":"custom-ilm-ado-policy-conditions-using-plsql","status":"publish","type":"post","link":"https:\/\/blog.sqlora.com\/de\/custom-ilm-ado-policy-conditions-using-plsql\/","title":{"rendered":"Benutzerdefinierte ILM ADO Bedingungen mit PL\/SQL"},"content":{"rendered":"<p>In meinem <a href=\"http:\/\/blog.sqlora.com\/en\/ilm-storage-tiering\/\">post \u00fcber ILM storage tiering<\/a> habe ich \u00fcber ADO-Bedingungen geschrieben, die wir f\u00fcr Storage Tiering Policies angeben k\u00f6nnen, wenn  Datensegmente in einen Read Only Tablespace verschoben werden. Andere M\u00f6glichkeit, Storage Tiering mit einer Bedingung zu versehen w\u00e4re eine benutzerdefinierte PL\/SQL-Funktion, die einen Boolean-Wert zur\u00fcckgibt. Wie funktioniert das? Und k\u00f6nnen wir auf die Heat Map Information zur\u00fcckgreifen? <!--more--><\/p>\n<p>Leider gibt die Dokumentation auf den ersten Blick nicht so viel Information her:<br \/>\n<code><br \/>\n<strong>ON<\/strong><br \/>\nUse this clause to specify a PL\/SQL function that returns a boolean value. For <strong>function_name<\/strong>, specify the name of the function. The policy will take effect when the function returns <strong>TRUE<\/strong>.<br \/>\n<\/code><br \/>\nEin gutes Beispiel ist im Blog von <a href=\"https:\/\/uhesse.com\/2013\/12\/09\/ado-storage-tiering-with-customized-function-example\/\" rel=\"noopener\" target=\"_blank\"> Uwe Hesse<\/a> zu finden. Das Beispiel verwendet eine einfache Funktion im Sinne einer EIN\/AUS-Logik. Wahrscheinlich war es auch der Grund, warum ich den entscheidenden Punkt lange \u00fcbersehen hatte. I habe mich gefragt, ob es oft Sinn macht, eine benutzerdefinierte Bedingung zu definieren, die nicht in Kenntniss von Objekten ist, f\u00fcr die die Bedingung \u00fcberpr\u00fcft wird? Wenn nicht, wie \u00fcbergeben wir die Informationen zu diesen Objekten? Und endlich habe ich den Parameter der Funktion gesehen (der gar nicht verwendet wurde)! Die Funktion akzeptiert OBJECT_ID als Parameter. <\/p>\n<p>Seit dem war es wie mit dem  <a href=\"https:\/\/en.wikipedia.org\/w\/index.php?title=Baader-Meinhof_phenomenon&#038;redirect=no\" rel=\"noopener\" target=\"_blank\">Baader-Meinhof Ph\u00e4nomen (Frequency Illusion)<\/a>: ich habe auch ein anderes gutes Beispiel im <a href=\"https:\/\/support.oracle.com\/epmos\/faces\/DocumentDisplay?id=1967038.1&#038;displayIndex=1&#038;_adf.ctrl-state=3zrdrpn6v_81&#038;_afrLoop=227184546313628\" rel=\"noopener\" target=\"_blank\">MOS Doc ID 1967038.1<\/a> gefunden und sogar <a href=\"http:\/\/docs.oracle.com\/database\/121\/VLDBG\/GUID-B011D86F-DCDE-4BF5-9C47-24B9650EFCA8.htm\" rel=\"noopener\" target=\"_blank\">eine Dokumentationsseite,<\/a> die &#8211; zwar nur im Beispiel &#8211;  die Existenz des Parameters f\u00fcr die Policy-Funktion zeigt. <\/p>\n<p>Das schauen wir uns an. Wir nehmen denselben Setup, wie f\u00fcr den <a href=\"http:\/\/blog.sqlora.com\/en\/ilm-storage-tiering\/\">vorherigen Beitrag \u00fcber ILM Storage Tiering.<\/a> Dieselbe Tabelle <strong>SCOTT.EMPLOYEE<\/strong> und derselbe Tablespace <strong>LOW_COST_STORE<\/strong>. We wollen, nachdem unsere benutzerdefinierte Bedingung als positiv evaluiert wurde, die Table zum neunen Tablespace verschieben. Wir  versuchen mal die ADO-Bedingung  <strong>&#8222;AFTER 10 DAY OF NO MODIFICATION&#8220;<\/strong> nachzubauen.<\/p>\n<p>Zuerst erstellen wir die Funktion zum Auswerten der gew\u00fcnschten Bedingung. Mit der als Parameter \u00fcbergebenen OBJECT_ID k\u00f6nnen wir aus der View <strong>USER_HEAT_MAP_SEGMENT<\/strong> die letzte Modifizierungszeit abfragen. Hier m\u00fcssen wir den Wert vom ILM-Paramater <strong><em>POLICY_TIME<\/em><\/strong> \u00fcberpr\u00fcfen, damit wir mit dessen \u00c4nderung f\u00fcr Testzwecke umgehen k\u00f6nnen. <\/p>\n<p>Nach dem Erstellen der Funktion, k\u00f6nnen wir bereits die Policy erstellen, die diese Funktion verwendet und die Informationen aus dem Data Dictionary anzeigen lassen. Beachten Sie, dass die Datenbank in dem Fall kein Wissen \u00fcber unsere Bedingung hat (CONDITION_DAYS=0).<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nCREATE OR REPLACE FUNCTION f_custom (p_object_id number) RETURN BOOLEAN IS\r\n  2  v_time NUMBER;\r\n  3  v_days_no_modification NUMBER := 10;\r\n  4  v_ilm_parameter number;\r\n  5  BEGIN\r\n  6    SELECT  sysdate-SEGMENT_WRITE_TIME\r\n  7    INTO    v_time\r\n  8    FROM    user_heat_map_segment\r\n  9    WHERE   object_name = (SELECT object_name FROM user_objects WHERE object_id=p_object_id);\r\n 10  \r\n 11    SELECT value\r\n 12    INTO v_ilm_parameter\r\n 13    FROM dba_ilmparameters WHERE name = &#039;POLICY TIME&#039;;\r\n 14  \r\n 15    IF v_ilm_parameter = 1 \/*DBMS_ILM_ADMIN.POLICY_IN_SECONDS*\/ THEN\r\n 16  \t v_time:=v_time*60*60*24;\r\n 17    END IF;\r\n 18  \r\n 19    RETURN v_time &gt; v_days_no_modification;\r\n 20  \r\n 21  END;\r\n 22  \/\r\n\r\nFunction created.\r\n\r\nSCOTT&gt; -- Storage tiering with user defined condition function\r\nSCOTT&gt; ALTER TABLE scott.employee1  ILM ADD POLICY TIER TO low_cost_store ON f_custom;\r\n\r\nTable altered.\r\n\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; -- Show ILM policy information\r\nSCOTT&gt; ----------------------------------------------------------------------------------------------------\r\nSCOTT&gt; SELECT policy_name, action_type, scope, tier_tablespace\r\n  2    ,      condition_type, condition_days, custom_function\r\n  3    FROM   user_ilmdatamovementpolicies;\r\n\r\nPOLICY_NAME ACTION_TYPE SCOPE\tTIER_TABLESPACE  CONDITION_TYPE         CONDITION_DAYS  CUSTOM_FUNCTION\r\n----------- ----------- ------- ---------------- ---------------------- --------------  ------------------\r\nP261\t    STORAGE     SEGMENT LOW_COST_STORE\t USER DEFINED           0               F_CUSTOM\r\n\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          OBJECT_TYPE\t    ENABLED\r\n----------- -------------------- ------------------ -------\r\nP261\t    EMPLOYEE1            TABLE              YES\r\n<\/pre>\n<p>Jetzt stellen wir das Heat Map wieder f\u00fcr Testzwecke auf die Sekundeneinheiten um, aktualisieren die Tabelle und lassen die Heat Map Information wegschreiben. Die Abfrage von <strong>USER_HEAT_MAP_SEGMENT<\/strong> zeigt die letzte \u00c4nderungszeit WRITE_TIME f\u00fcr die Tabelle EMPLOYEE1. Wir f\u00fchren ILM manuell aus und pr\u00fcfen, wo die Table EMPLOYEE1 jetzt ist. Nichts passiert? Die Abfrage zeigt weiterhin den Tablespace  USERS an. Ist aber auch richtig so &#8211; wir haben keine 10 Sekunden abgewartet. Die View <strong>USER_ILMEVALUATIONDETAILS<\/strong> best\u00e4tigt das: PRECONDITION NOT SATISFIED.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSCOTT&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\nSCOTT&gt; -- 2. set start date\r\nSCOTT&gt; EXECUTE DBMS_ILM_ADMIN.SET_HEAT_MAP_START(sysdate -50);\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; UPDATE scott.employee1 e SET e.empno = e.empno+1;\r\n\r\n3584 rows updated.\r\n\r\nSCOTT&gt; commit;\r\n\r\nCommit complete.\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; EXECUTE dbms_ilm.flush_all_segments;\r\n\r\nPL\/SQL procedure successfully completed.\r\n\r\nSCOTT&gt; SELECT\tobject_name, to_char(segment_write_time,&#039;DD-MON-YY hh24:mi:ss&#039;) write_time\r\n  2  FROM\tuser_heat_map_segment\r\n  3  WHERE\tobject_name =&#039;EMPLOYEE1&#039;;\r\n\r\nOBJECT_NAME\t     WRITE_TIME\r\n-------------------- ---------------------------\r\nEMPLOYEE1\t     21-OCT-17 11:03:50\r\n\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 EMPLOYEE1 was NOT 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=&#039;EMPLOYEE1&#039;;\r\n\r\nTABLESPACE_NAME \t       SEGMENT_NAME\r\n------------------------------ --------------------\r\nUSERS\t\t\t       EMPLOYEE1\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; select task_id, object_name, selected_for_execution from user_ilmevaluationdetails;\r\n\r\n   TASK_ID OBJECT_NAME\t\tSELECTED_FOR_EXECUTION\r\n---------- -------------------- ------------------------------------------\r\n       219 EMPLOYEE1\t\tPRECONDITION NOT SATISFIED\r\n\r\n<\/pre>\n<p>Dann warten wir 10 Sekunden und wiederholen den Versuch. Jetzt wurde die Tabelle EMPLOYEE1 in den neuen Tablespace verschoben.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nSCOTT&gt; EXECUTE\tdbms_lock.sleep(10);\r\n\r\nPL\/SQL procedure successfully completed.\r\n\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 EMPLOYEE1 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=&#039;EMPLOYEE1&#039;;\r\n\r\nTABLESPACE_NAME \t       SEGMENT_NAME\r\n------------------------------ --------------------\r\nLOW_COST_STORE\t\t       EMPLOYEE1\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; SELECT task_id, to_char(start_time, &#039;dd\/mm\/yyyy hh24:mi:ss&#039;) as start_time, u.STATE\r\n  2  FROM user_ilmtasks u;\r\n\r\n   TASK_ID START_TIME\t       STATE\r\n---------- ------------------- ---------\r\n       219 21\/10\/2017 11:03:52 COMPLETED\r\n       220 21\/10\/2017 11:04:13 COMPLETED\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; select task_id, job_name, job_state, to_char(completion_time, &#039;dd\/mm\/yyyy hh24:mi:ss&#039;) 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       220 ILMJOB4212\t   COMPLETED SUCCESSFULLY\t       21\/10\/2017 11:04:14\r\n\r\nSCOTT&gt; \r\nSCOTT&gt; select task_id, object_name, selected_for_execution from user_ilmevaluationdetails;\r\n\r\n   TASK_ID OBJECT_NAME\t\tSELECTED_FOR_EXECUTION\r\n---------- -------------------- ------------------------------------------\r\n       219 EMPLOYEE1\t\tPRECONDITION NOT SATISFIED\r\n       220 EMPLOYEE1\t\tSELECTED FOR EXECUTION\r\n\r\n<\/pre>\n<p>Es funktioniert also. Wenn man statt zu warten, bis der Schwellenwert beim Tablespace erreicht wird, die Storage Tiering Policies wie f\u00fcr Compression Tiering auch auf Heat Map Information basieren will, kann man es  mit Hilfe benutzerdefinierter Funktionen erreichen. Leider verliert man dabei ein gutes St\u00fcck Transparenz und Selbstdokumentation, weil die Bedingungen nicht im Data Dictionary gespeichert werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In meinem post \u00fcber ILM storage tiering habe ich \u00fcber ADO-Bedingungen geschrieben, die wir f\u00fcr Storage Tiering Policies angeben k\u00f6nnen, wenn Datensegmente in einen Read Only Tablespace verschoben werden. Andere M\u00f6glichkeit, Storage Tiering mit einer Bedingung zu versehen w\u00e4re eine benutzerdefinierte PL\/SQL-Funktion, die einen Boolean-Wert zur\u00fcckgibt. Wie funktioniert das? Und k\u00f6nnen wir auf die Heat [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,1,3,22],"tags":[46,48,24],"class_list":["post-357","post","type-post","status-publish","format-standard","hentry","category-12c","category-allgemein","category-oracle","category-trivadis","tag-information-lifecycle-management","tag-storage-tiering","tag-12c"],"_links":{"self":[{"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/posts\/357","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/comments?post=357"}],"version-history":[{"count":13,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/posts\/357\/revisions"}],"predecessor-version":[{"id":384,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/posts\/357\/revisions\/384"}],"wp:attachment":[{"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/media?parent=357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/categories?post=357"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.sqlora.com\/de\/wp-json\/wp\/v2\/tags?post=357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}