12c Enhanced Online Index DDL Operations (Lady Godiva’s Operation) February 17, 2014
Posted by Richard Foote in 12c, Drop Index, Invisible Indexes, Online DDL, Oracle Indexes, Unusable Indexes.trackback
In my last couple of posts, I discussed how table partitions can be moved online since 12c, keeping all indexes in sync as part of the process.
12c also introduced enhancements to a number of index related DDL statements, removing blocking locks and making their use online and far less intrusive. The following commands now have a new ONLINE option:
DROP INDEX ONLINE
ALTER INDEX UNUSABLE ONLINE
So if we look at a little example (initially on 11g R2), where we create a table and associated index on the CODE column:
SQL> create table radiohead (id number, code number, name varchar2(30)); Table created. SQL> insert into radiohead select rownum, mod(rownum,1000), 'DAVID BOWIE' from dual connect by level <= 1000000; 1000000 rows created. SQL> commit; Commit complete. SQL> create index radiohead_code_i on radiohead(code); Index created.
If we now insert a new row in one session but not commit:
SQL> insert into radiohead values (1000001, 42, 'ZIGGY STARDUST'); 1 row created.
And then attempt any of the following DDL commands in another session:
SQL> drop index radiohead_code_i; drop index radiohead_code_i * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
SQL> alter index radiohead_code_i invisible; alter index radiohead_code_i invisible * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
SQL> alter index radiohead_code_i unusable; alter index radiohead_code_i unusable * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
They all get the well-known “ORA-00054: resource busy” error.
If on the other hand, one of these DDL statements is already running in a session:
SQL> alter index radiohead_code_i unusable;
All DML statements in other sessions will hang until the DDL completes:
SQL> insert into radiohead values (1000002, 42, 'THIN WHITE DUKE');
Once the index is finally made unusable:
SQL> alter index radiohead_code_i unusable; Index altered. SQL> select index_name, status from dba_indexes where index_name = 'RADIOHEAD_CODE_I'; INDEX_NAME STATUS ------------------------------ -------- RADIOHEAD_CODE_I UNUSABLE SQL> select segment_name, blocks, extents from dba_segments where segment_name = 'RADIOHEAD_CODE_I'; no rows selected
We can see not only is the index now in an unusable state but the index segment has been dropped (in 11g r2) as the storage associated with the unusable index is of no further use.
So these commands prior to the Oracle 12c Database previously had locking related issues.
If we now perform the same setup in 12c and again have an outstanding transaction in a session:
SQL> drop index radiohead_code_i online;
The Drop Index command doesn’t now get the Ora-00054: resource busy, but rather hangs until all prior transactions complete.
However, while the Drop Index command hangs, it doesn’t in turn lock out transactions within other sessions. In another session:
SQL> insert into radiohead values (1000002, 42, 'THIN WHITE DUKE'); 1 row created.
And in yet other session:
SQL> delete radiohead where id = 42; 1 row deleted. SQL> commit; Commit complete.
These all complete successfully. The Drop Index command itself will eventually complete successfully once all prior transaction have finished.
SQL> drop index radiohead_code_i online; Index dropped.
Another more subtle difference in behaviour with 12c. If there’s an existing transaction when you decide to make an index unusable:
SQL> insert into radiohead values (1000001, 42, 'ZIGGY STARDUST'); 1 row created.
SQL> alter index radiohead_code_i unusable online;
As in the previous demo, the alter index command will hang indefinitely until the previous transaction commits:
SQL> commit; Commit complete. SQL> alter index radiohead_code_i unusable online; Index altered. SQL> select index_name, status from dba_indexes where index_name = 'RADIOHEAD_CODE_I'; INDEX_NAME STATUS ------------------------- -------- RADIOHEAD_CODE_I UNUSABLE SQL> select segment_name, blocks, extents from dba_segments where segment_name = 'RADIOHEAD_CODE_I'; SEGMENT_NAME BLOCKS EXTENTS ---------------- ---------- ---------- RADIOHEAD_CODE_I 2176 32
We note the index has eventually been made Unusable, however the segment has not now been dropped (as it was in the 11g R2 demo) due to the use of the ONLINE clause.
With the Oracle 12c Database, the locking implications and concurrency issues associated these index related DDL commands have been reduced with these new ONLINE options.
Thanks Richard!! This is really helping option.
LikeLike
Hi Richard.
Just a tiny correction – ALTER INDEX VISIBLE|INVISIBLE is always an online operation in 12c. You cannot specify the ONLINE keyword.
Thanks,
Oren.
LikeLike
Thanks Oren, nice catch.
LikeLike
Hi,
on DB ver.: 12.1.0.2 and also on 11.2.0.3 :
when I alter index unusable, it’s still present in the segments,
which process (JOB?) is supposed to drop this segment?
Thanks.
Best regards,
Daniel.
LikeLike
Additional info, this was a global function based index on a sub-partitioned table.
For regular indexes on a non-partitioned tables the segment is indeed being dropped on both versions.
LikeLike
Hi Daniel
There is no job, these should be dropped during the DDL operation. I don’t have time to test, sounds like a bug.
LikeLike