Information Lifecycle Management ist zwar kein neuer Begriff in der Version 12c, wurde aber um zwei sehr praktische Features bereichert: Heat Map and ADO (Automatic Data Optimization). das letztere erlaubt es, die Regeln (Policies) für Datensegmente zu definieren, die wiederum aus Bedingungen und Aktionen bestehen. Die Bedingungen werden grundsätzlich anhand der mit Heat Map gesammelten Informationen überprüft und dann werden die definierten Aktionen ausgeführt: Daten komprimieren (compression tiering) oder Daten verschieben (storage tiering). „Grundsätzlich“, weil man zum einen benutzerdefinierte Bedingungen (PL/SQL-Funktionen) verwenden kann, die nicht zwingend auf die Heat Map Informationen zurückgreifen, und zum zweiten, weil es eine Art Unklarheit herrscht, wie und ob man die Bedingungen für Storage Tiering auch angeben kann.
In 12.1 war das Syntaxdiagram für die ILM-Klausel irreführend, da es suggeriert, dass man Policies basieren auf Bedingungen definieren kann.
Offensichtlich war das ein Bug in der Dokumentation. Das hat einfach nicht funktioniert:
SCOTT> ALTER TABLE scott.employee 2 ILM ADD POLICY TIER TO low_cost_store 3 SEGMENT AFTER 10 DAYS OF NO MODIFICATION; SEGMENT AFTER 10 DAYS OF NO MODIFICATION * ERROR at line 3: ORA-01735: invalid ALTER TABLE option SCOTT> ALTER TABLE scott.employee ILM ADD POLICY TIER TO low_cost_store; Table altered.
Außer benutzerdefinierter Bedingungen mit Hilfe der PL/SQL-Funktionen hat nur die einfachste Form ohne Bedingung funktioniert. Die Entscheidung, wann das Verschieben der Datensegmente starten soll, hängt hier alleine vom verfügbaren freien Platz im Tablespace. ADO-Parameter TBS_PERCENT_USED und TBS_PERCENT_FREE steuern dabei das Verhalten. Oracle’s White Paper erklärt das Verhalten so:
The justification for making storage tiering dependent on „space pressure“ 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 ‚READ ONLY‘ option, these are triggered by a heat-map based condition clause.
Ich persönlich kann die Argumentation nicht 100% nachvollziehen. Auch wenn sich das logisch anhört, warum hat man die Option weggelassen, die Bedingungen ähnlich wie für Compression Tiering angeben zu können? Schließlich sollte man es in der Lage sein, über PL/SQL-Funktionen selber zu programmieren. Aber der letzte Satz hat mich hellhörig gemacht: geht da doch was? Hat sich die Dokumentation geändert?
Die 12.2 Dokumentation bietet eine korrigierte Version des Sysntaxdiagrams für Storage Tiering (jetzt auch separat vom Compression Tiering):
Laut dem soll es wirklich möglich sein, Bedingungen angeben zu können, aber nur für den Fall, dass die Daten in ein Read-Only Tablespace verschoben werden.
Funktioniert es wirklich so wie beschrieben? Wir probieren es und nehmen als Grundlage Oracle’s Beispiel.
Als erstes legen wir den Tablespace, in den die Daten verschoben werden und setzten ihn auf Read-Only. Wichtig: dieser Tablespace wird zum Verschieben der Daten auf Read-Write umgestellt und dann wieder zurück auf Read-Only. Aus diesem Grund braucht der Benutzer SCOTT die ALTER TALESPACE Rechte.
SYS> create tablespace low_cost_store 2 datafile '&_data_path/lowcoststore01.dbf' size 1M ; Tablespace created. SYS> SYS> alter tablespace low_cost_store read only; Tablespace altered. SYS> SYS> grant alter tablespace, select any dictionary to scott; Grant succeeded. SYS> --------------------------------------------------------- SYS> -- Table EMPLOYEE is stored in default tablespace USERS SYS> --------------------------------------------------------- SYS> SELECT owner, segment_name, tablespace_name 2 FROM dba_segments 3 WHERE segment_name = 'EMPLOYEE'; OWNER SEGMENT_NAME TABLESPACE_NAME ---------- -------------------- ------------------------------ SCOTT EMPLOYEE USERS
Nun erstellen wir die Policy zum Verschieben der Daten nach zehn Tagen ohne Änderungen und lassen es über Data Dictionary verifizieren. Bemerkenswert hier: wir haben ACTION_TYPE=“STORAGE“ und trotzdem ist CONDITION_TYPE gesetzt.
SCOTT> -- Storage tiering with condition only to move to read-only tablespace SCOTT> ALTER TABLE scott.employee 2 ILM ADD POLICY TIER TO low_cost_store READ ONLY 3 SEGMENT AFTER 10 DAYS OF NO MODIFICATION; Table altered. SCOTT> SCOTT> ---------------------------------------------------------------------------- SCOTT> -- Show ILM policy information SCOTT> ---------------------------------------------------------------------------- SCOTT> SELECT policy_name, action_type, scope, tier_tablespace, condition_type, condition_days 2 FROM user_ilmdatamovementpolicies; POLICY_NAME ACTION_TYPE SCOPE TIER_TABLESPACE CONDITION_TYPE CONDITION_DAYS ----------- ----------- ------- ---------------- ---------------------- -------------- P162 STORAGE SEGMENT LOW_COST_STORE LAST MODIFICATION TIME 10 SCOTT> SCOTT> SELECT policy_name, object_name, object_type, enabled 2 FROM user_ilmobjects; POLICY_NAME OBJECT_NAME OBJECT_TYPE ENABLED ----------- -------------------- ------------------ ------- P162 EMPLOYEE TABLE YES
Als nächstes machen wir den Trick mit dem Setzten der ILM Evaluierungszeit auf die Sekunden statt Tage, wir im Oracle’s Beispiel gezeigt, lassen Heat Map Informationen auf die Platte schreiben und warten mehr als zehn Sekunden:
SYS> -- 1. Switch ILM unit to seconds SYS> EXECUTE dbms_ilm_admin.customize_ilm(DBMS_ILM_ADMIN.POLICY_TIME, DBMS_ILM_ADMIN.ILM_POLICY_IN_SECONDS); PL/SQL procedure successfully completed. SYS> -- 2. set start date SYS> EXECUTE DBMS_ILM_ADMIN.SET_HEAT_MAP_START(start_date => sysdate - 50); PL/SQL procedure successfully completed. SYS> EXECUTE dbms_ilm.flush_all_segments; PL/SQL procedure successfully completed. SYS> EXECUTE dbms_lock.sleep(15); PL/SQL procedure successfully completed.
Dann führen wir den ILM-Job manuell aus und sehen, was passiert. Die Tabelle wurde in den neuen Tablespace low_cost_store verschoben. ILM-Task wurde ausgeführt wie erwartet.
SCOTT> ---------------------------------------------------------------------------------------------------- SCOTT> -- Run ILM data movement task SCOTT> ---------------------------------------------------------------------------------------------------- SCOTT> 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. SCOTT> ---------------------------------------------------------------------------------------------------- SCOTT> -- Table EMPLOYEE is now moved to tablespace LOW_COST_STORE SCOTT> -------------------------------------------------------------------------------------------------- SCOTT> select tablespace_name, segment_name 2 from user_segments 3 where segment_name='EMPLOYEE'; TABLESPACE_NAME SEGMENT_NAME ------------------------------ -------------------- LOW_COST_STORE EMPLOYEE 1 row selected. SCOTT> ---------------------------------------------------------------------------------------------------- SCOTT> -- Show ILM task results SCOTT> -------------------------------------------------------------------------------------------------- SCOTT> SELECT task_id, to_char(start_time, 'dd/mm/yyyy hh24:mi:ss') as start_time 2 FROM user_ilmtasks; TASK_ID START_TIME ---------- ------------------- 162 12/10/2017 14:50:24 1 row selected. SCOTT> select task_id, job_name, job_state, to_char(completion_time, 'dd/mm/yyyy hh24:mi:ss') completion 2 from user_ilmresults; TASK_ID JOB_NAME JOB_STATE COMPLETION ---------- --------------- ----------------------------------- ------------------------------ 162 ILMJOB4148 COMPLETED SUCCESSFULLY 12/10/2017 14:50:26 1 row selected.
Ich habe es auch in 12.1.0.1 getestet – es geht! Es war offensichtlich kein Enhancement oder Bugfix vom Release 12.1.0.2 oder 12.2.0.1, sondern einfach ein Bug der Dokumentation. Und übrigens die Dokumentation wurde nun auch rückwirkend für 12.1 korrigiert!