Introduction In today's article, I am going to discuss about yet another cool feature introduced with Oracle Database 12c. This feature provides an ability to the data to make itself invisible when desired. You might have already figured out the context of this article. Yes, I am taking about the In Database Archiving (row archival) feature introduced with Oracle database 12c; which lets us archive the data within the same database table without a need to move them to a different archive store. What is In Database Archiving (row archival)? Archiving is generally defined as process of moving INACTIVE data to a different storage device for long term retention. In database archiving (Raw Archival) provides us the feature of marking these INACTIVE data as ARCHIVED within the same table without actually moving them to a separate storage device, which means the data can still be present in the same database tables without visibility to the application queries. This feature is typically useful to applications, where there is a requirement to mark application data as deleted/inactive (archived) without physically deleting (moving them to separate storage) those data. Prior to Oracle Database 12c, this type of requirements were met by defining an additional column in the database table with specific flags indicating particular table record is archived (deleted) and then making necessary adjustments in application queries to check this flag while querying data. Raw Archival also provides additional benefits such as compression and keeping archived data in low tier storage units apart from archiving the data in the same table. In today's article we will explore the basic row archival feature. We will discuss about the additional benefits in a separate article. How to enable row archival In Database Archiving is defined at the table level by means of a new clause called ROW ARCHIVAL . Including this clause in a table definition indicates that the table records are enabled for archiving. A table can be either created as row archival enabled by means of CREATE TABLE statement or can be later enabled for row archival by means of ALTER TABLE command. When we enable a table for row archival, Oracle creates an additional (HIDDEN) column named as ORA_ARCHIVE_STATE for that table. This column (ORA_ARCHIVE_STATE) controls whether a table record is ACTIVE or ARCHIVED. By default the column ORA_ARCHIVE_STATE is set to a value of 0 for each table record, which indicates the data is ACTIVE. Example: Lets quickly go through an example for enabling row archival for a database table ----// ----// Creating table with row archival enabled //---- ----// SQL> create table test_data_archival 2 ( 3 id number not null, 4 name varchar(20) not null, 5 join_date date not null 6 ) 7 row archival; Table created. ----// ----// Populate the table with some data //---- ----// SQL> insert into test_data_archival 2 select rownum, rpad('X',15,'X'), sysdate 3 from dual connect by rownum commit; Commit complete. SQL> select count(*) from test_data_archival; COUNT(*) ---------- 500 In this example we have created a table (test_data_archival) with in database archiving (row archival) enabled and populated it with some dummy data (500 records with ID ranges from 1 to 500). We can also enable row archival for existing tables by specifying the ROW ARCHIVAL clause along with the ALTER TABLE statement as shown below. ----// ----// Enabling row archival for existing tables //---- ----// SQL> alter table test_data_arch row archival; Table altered. Note: Trying to enable row archival for a table which is already enabled for row archival, will result into errors similar to the following ----// SQL> alter table test_data_archival row archival; alter table test_data_archival row archival * ERROR at line 1: ORA-38396: table is already enabled for the ILM feature Validating row archival We can't identify if a table is enabled for row archival by just describing (DESC) the table as that would not show different output for a general table and for table with row archival enabled. Since the column ORA_ARCHIVE_STATE (that controls in database archiving)is in hidden state, it is not displayed using DESC command. ----// ----// DESC command doesn't indicate if row archival is enabled or not //---- ----// SQL> desc test_data_archival Name Null? Type ----------------------------------------- -------- ---------------------------- ID NOT NULL NUMBER NAME NOT NULL VARCHAR2(20) JOIN_DATE NOT NULL DATE However, we can query the DBA/USER/ALL_TAB_COL views to validate if a table is enabled for row archival. If a table has the ORA_ARCHIVE_STATE hidden column listed in these views, then the table is enabled for row archival. ----// ----// query DBA_TAB_COLS to check if we have the HIDDEN column //---- ----// ORA_ARCHIVE_STATE available for the database table //---- ----// SQL> select owner,table_name,column_id,column_name,hidden_column 2 from dba_tab_cols where table_name='TEST_DATA_ARCHIVAL' order by column_id; OWNER TABLE_NAME COLUMN_ID COLUMN_NAME HID ---------- -------------------- ---------- -------------------- --- MYAPP TEST_DATA_ARCHIVAL 1 ID NO 2 NAME NO 3 JOIN_DATE NO ORA_ARCHIVE_STATE YES ---> This column indicates the table is enabled for row archival Another way to check, if a table is defined for row archival is to check the table metadata. If the table metadata has a clause "ILM ENABLE LIFECYCLE MANAGEMENT" , then it indicates that the table is enabled for row archival. However, this is only applicable to Oracle Database 12c release 12.1.0.2 ----// ----// query table metadata to validate row archival enabled or not //---- ----// SQL> select dbms_metadata.get_ddl('TABLE','TEST_DATA_ARCHIVAL') ddl from dual; DDL -------------------------------------------------------------------------------- CREATE TABLE "MYAPP"."TEST_DATA_ARCHIVAL" ( "ID" NUMBER NOT NULL ENABLE, "NAME" VARCHAR2(20) NOT NULL ENABLE, "JOIN_DATE" DATE NOT NULL ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "APPDATA" ILM ENABLE LIFECYCLE MANAGEMENT ---> This clause indicates that the table is enabled for row archival ILM (Information Lifecycle Management) is Oracle Database feature that helps to manage data by storing them into different storage and compression tiers based on a Organizations business and performance needs. Raw Archival is ILM feature and hence the table definition has a clause indicating the same. For more details about ILM, please refer here Archiving table data As mentioned earlier, by default Oracle populates the ORA_ARCHIVE_STATE column with a value of 0 (zero), which indicates the table data is in ACTIVE state. This can be verified as follow. ----// ----// validate default value for ORA_ARCHIVE_STATE column //---- ----// SQL> select ora_archive_state,count(*) from test_data_archival group by ora_archive_state; ORA_ARCHIVE_STATE COUNT(*) -------------------- ---------- 0 500 We had populated 500 records in our table and we can see all these records have a value 0 (zero) for the row archival column ORA_ARCHIVE_STATE. This means all of these records are ACTIVE and application queries can access them. To mark a table record ARCHIVED, we need to update the row archival column ORA_ARCHIVE_STATE for that record to a value 1. This is done through a procedure call to DBMS_ILM.ARCHIVESTATENAME . The syntax for marking table record as ARCHIVED is as follows ----// ----// Syntax for archiving data using row archival feature //---- ----// UPDATE table_name SET ORA_ARCHIVE_STATE=DBMS_ILM.ARCHIVESTATENAME(1) where column_predicates Example: Lets say we want to archive the records with ID 100 and 200 in TEST_DATA_ARCHIVAL table. This can be done as follows. ----// ----// Querying records before archiving //---- ----// SQL> select * from test_data_archival where id in (100,200); ID NAME JOIN_DATE ---------- -------------------- --------- 100 XXXXXXXXXXXXXXX 19-SEP-15 200 XXXXXXXXXXXXXXX 19-SEP-15 ----// ----// Archive records with ID 100 and 200 using row archival //---- ----// SQL> update test_data_archival 2 set ora_archive_state=dbms_ilm.archivestatename(1) 3 where id in (100,200); 2 rows updated. SQL> commit; Commit complete. ----// ----// Querying records after archiving //---- ----// SQL> select * from test_data_archival where id in (100,200); no rows selected ----// ----// Row count also excludes the archived records //---- ----// SQL> select count(*) from test_data_archival; COUNT(*) ---------- 498 As we can see, we were able to query the table records before archiving them using row archival feature. However, the records went invisible once we archived them using the row archival feature. These archived records are still present in the database and we can view them if desired as explained in the next section. Note: We can even use the generic update command like " UPDATE table_name SET ORA_ARCHIVE_STATE=0 WHERE column_predicates" to mark the data as ARCHIVED. We can even set the value of ORA_ARCHIVE_STATE to anything other than 0 (zero) to indicate the table record is ARCHIVED. However, the ILM package only recognizes the value 1 (one) as INACTIVE and 0 (zero) as ACTIVE. Setting ORA_ARCHIVE_STATE other than these values may impact the ILM functionalities. Viewing archived records Once we archive table records using the row archival feature (by means of DBMS_ILM.ARCHIVESTATENAME procedure), the records are no longer visible to application queries. However, there is a way we can view those archive records. We can enable a database session to view the archived rows by setting the parameter ROW ARCHIVAL VISIBILITY to the value ALL as shown below ----// ----// Enable database session to view archived records //---- ----// SQL> alter session set ROW ARCHIVAL VISIBILITY=ALL; Session altered. ----// ----// Query the archived records //---- ----// SQL> select * from test_data_archival where id in (100,200); ID NAME JOIN_DATE ---------- -------------------- --------- 100 XXXXXXXXXXXXXXX 19-SEP-15 200 XXXXXXXXXXXXXXX 19-SEP-15 ----// ----// Row count includes archived records too //---- ----// SQL> select count(*) from test_data_archival; COUNT(*) ---------- 500 We can set the same session parameter ROW ARCHIVAL VISIBILITY to the value ACTIVE to prevent a database session from viewing archived records as show below ----// ----// with session's visibility to archived records set to ALL //---- ----// SQL> select count(*) from test_data_archival; COUNT(*) ---------- 500 ----// ----// change session's visibility to for archived records to ACTIVE //---- ----// SQL> alter session set ROW ARCHIVAL VISIBILITY=ACTIVE; Session altered. SQL> select count(*) from test_data_archival; COUNT(*) ---------- 498 Restoring archived data In Database Archival (row archival) makes it very easy to restore the archived data back to its original state. Since the data is archived within the same database table (It is just marked as ARCHIVED), we just need to change the state of the archived record as ACTIVE by setting the row archival column ORA_ARCHIVE_STATE back to the value 0 (zero). This can be done by calling the DBMS_ILM.ARCHIVESTATENAME procedure. However, before the archived data can be marked as ACTIVE (restored), we need to have visibility to the archived data. This is why the restoration of archived data is a two phase process as listed below Change ROW ARCHIVAL VISIBILITY to ALL Restore (mark data as ACTIVE) by updating it through DBMS_ILM.ARCHIVESTATENAME procedure using the following syntax ----// ----// syntax for restoring archived data from row archival //--- ----// UPDATE table_name SET ORA_ARCHIVE_STATE=DBMS_ILM.ARCHIVESTATENAME(0) WHERE column_predicates Example: In the following example, I am restoring the archived record having ID 100 for table TEST_DATA_ARCHIVAL ----// ----// restoring archived record without ROW ARCHIVAL VISIBILITY is not permitted //--- ----// SQL> update test_data_archival 2 set ora_archive_state=dbms_ilm.archivestatename(0) 3 where id=100; 0 rows updated. ----// ----// change ROW ARCHIVAL VISIBILITY to ALL //---- ----// SQL> alter session set ROW ARCHIVAL VISIBILITY=ALL; Session altered. ----// ----// restore (mark record as ACTIVE) archived record with ID=100 //---- ----// SQL> update test_data_archival 2 set ora_archive_state=dbms_ilm.archivestatename(0) 3 where id=100; 1 row updated. SQL> commit; Commit complete. ----// ----// validate if we can query the record with ROW ARCHIVAL VISIBILITY being set to ACTIVE //---- ----// SQL> alter session set ROW ARCHIVAL VISIBILITY=ACTIVE; Session altered. SQL> select * from test_data_archival where id=100; ID NAME JOIN_DATE ---------- -------------------- --------- 100 XXXXXXXXXXXXXXX 19-SEP-15 Disabling Raw Archival We can disable Raw Archival for a table using NO ROW ARCHIVAL clause with ALTER TABLE statement and the syntax is. ----// ----// syntax for disabling Raw Archival for a table //---- ----// ALTER TABLE table_name NO ROW ARCHIVAL; Example: In the following example, I am disabling Raw Archival for table TEST_DATA_ARCHIVAL ----// ----// Record count with row archival being enabled //---- ----// SQL> select count(*) from test_data_archival; COUNT(*) ---------- 499 ----// ----// disable row archival for table //---- ----// SQL> alter table test_data_archival no row archival; Table altered. ----// ----// Check if the hidden column ORA_ARCHIVE_STATE exists //---- ----// SQL> select owner,table_name,column_id,column_name,hidden_column,default_on_null 2 from dba_tab_cols where table_name='TEST_DATA_ARCHIVAL' order by column_id; OWNER TABLE_NAME COLUMN_ID COLUMN_NAME HID DEF ---------- -------------------- ---------- -------------------- --- --- MYAPP TEST_DATA_ARCHIVAL 1 ID NO NO 2 NAME NO NO 3 JOIN_DATE NO NO ----// ----// Record count after disabling Raw Archival //---- ----// SQL> select count(*) from test_data_archival; COUNT(*) ---------- 500 When we disable the Raw Archival for a table, the hidden column ORA_ARCHIVE_STATE gets dropped automatically, which in turn restores all the table records to ACTIVE state and gets visibility to application queries. Copying table (CTAS) with Raw Archival enabled When we create a copy of row archival enabled table with CTAS statement, the resulting tables doesn't get created with row archival enabled. Therefore all the table records become ACTIVE on the resulting table as show below ----// ----// Check count of records in table TEST_DATA_ARCH //---- ----// SQL> select count(*) from TEST_DATA_ARCH; COUNT(*) ---------- 500 ----// ----// Archive few records in the table TEST_DATA_ARCH //---- ----// SQL> update TEST_DATA_ARCH set ORA_ARCHIVE_STATE=1 where id commit; Commit complete. ----// ----// Check the count of records after row archival //----- ----// SQL> select count(*) from TEST_DATA_ARCH; COUNT(*) ---------- 400 ----// ----// Create a new table from TEST_DATA_ARCH using CTAS //---- ----// SQL> CREATE TABLE TEST_DATA_ARCH_COPY1 2 AS SELECT * FROM TEST_DATA_ARCH; Table created. ----// ----// Check the count of records on the resulting table //---- ----// SQL> select count(*) from TEST_DATA_ARCH_COPY1; COUNT(*) ---------- 500 As we can see, even though we had row archival enabled on our source table (TEST_DATA_ARCH), it did not propagate to the resulting table when we created that using CREATE TABLE AS SELECT statement. Conclusion We have explored the row archival (In Database Archiving) feature of Oracle Database 12c and how it can be used as a local archive store for storing INACTIVE data rather than moving the data to a remote archive store. This feature would be very useful for specific set of applications where we have a requirement to mark the data as ARCHIVED within the database itself so that the data is not visible to application queries; however is ready to be restored when desired. Row archival also speeds up the archiving process as we do not have to run expensive select/insert/delete queries to archive table records. We will explore few other aspects (benefits and considerations) of this new feature in a upcoming article. Till then stay tuned...
↧