IMPORTANT: This is not a recommendation to rebuild indexes.
The post will outline SQL used to determine index to rebuild.
PL/SQL will be used to check table lock for the underlying index and if there is no lock, then rebuild index else skip rebuild for index.
1.Download Index Sizing and create copy index_est_proc_2.sql.org
2. Create table index_rebuild.
SQL> desc index_rebuild Name Null? Type ----------------------------------------- -------- ---------------------------- TABLE_OWNER NOT NULL VARCHAR2(30) TABLE_NAME NOT NULL VARCHAR2(30) INDEX_NAME NOT NULL VARCHAR2(20) LEAF_BLOCKS NUMBER TARGET_SIZE NUMBER SQL>
3. Update index_est_proc_2.sql and include the following insert into table index rebuild.
if m_leaf_estimate < &m_scale_factor * r.leaf_blocks then dbms_output.put_line( to_char(sysdate,'hh24_mi_ss') || '|table|' || trim(r.table_name) || '|index|' || trim(r.index_name) || '|' || 'Current Leaf blocks|' || trim(to_char(r.leaf_blocks,'999,999,999')) || '|Target size|' || trim(to_char(m_leaf_estimate,'999,999,999')) ); -- Insert data into table index_rebuild as well as output to terminal. insert into index_rebuild(table_owner,table_name,index_name,leaf_blocks,target_size) values (UPPER('&m_owner'),trim(r.table_name),trim(r.index_name),r.leaf_blocks,m_leaf_estimate); dbms_output.new_line; end if;
4. Create plsql_rebuild_idx.sql
set timing on time on serveroutput on size unlimited trimsp on tab off lines 200 col TABLE_OWNER for a30 col TABLE_NAME for a30 col INDEX_NAME for a35 col USERNAME for a10 col MACHINE for a10 col MODULE for a30 -- Display current user session info. select s.username as Username, s.machine as Machine, s.module as Module, s.sid as SessionID, p.pid as ProcessID, p.spid as "UNIX ProcessID" from v$session s, v$process p where s.sid = sys_context ('userenv','sid') and s.PADDR = p.ADDR ; set echo on -- Rebuild indexes with LEAF_BLOCKS < 16000000 and edit as required. select * from index_rebuild where LEAF_BLOCKS < 16000000; exit lock table index_rebuild in EXCLUSIVE mode WAIT 120; DECLARE l_sql varchar2(1000); l_ct number; BEGIN FOR d in ( select TABLE_OWNER, TABLE_NAME, INDEX_NAME, LEAF_BLOCKS from index_rebuild order by leaf_blocks asc ) LOOP select count(*) into l_ct from v$locked_object a, v$session b, dba_objects c where b.sid = a.session_id and a.object_id = c.object_id and c.object_type='TABLE' and c.owner=d.TABLE_OWNER and c.object_name=d.TABLE_NAME and d.LEAF_BLOCKS < 16000000; IF l_ct = 0 THEN dbms_output.put_line( '-- Check lock for owner|table|index : ' ||d.TABLE_OWNER||'.'||d.TABLE_NAME||'.'||d.INDEX_NAME||'='||l_ct ); l_sql := 'alter index '||d.TABLE_OWNER||'.'||d.INDEX_NAME||' rebuild online parallel 4'; dbms_output.put_line (l_sql); execute immediate l_sql; delete from index_rebuild where TABLE_OWNER=d.TABLE_OWNER and TABLE_NAME=d.TABLE_NAME and INDEX_NAME=d.INDEX_NAME; END IF; END LOOP; END; / delete from index_rebuild; commit; exit
5. Run plsql_rebuild_idx.sql using nohup
nohup sqlplus "/ as sysdba" @ plsql_rebuild_idx.sql > plsql_rebuild_idx.log 2>&1 &
6. Review
$ cat plsql_rebuild_idx.log nohup: ignoring input SQL*Plus: Release 12.1.0.2.0 Production on Thu Sep 24 14:13:00 2020 Copyright (c) 1982, 2014, Oracle. All rights reserved. Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics and Real Application Testing options 14:13:00 SQL> select * from index_rebuild; TABLE_OWNER TABLE_NAME INDEX_NAME LEAF_BLOCKS TARGET_SIZE ------------------------------ ------------------------------ -------------------- ----------- ----------- XXXX YYYYYYYYYY1 ZZZZZZZZZZZ_M 9721430 4328586 XXXX YYYYYYYYYY2 ZZZZZZZZZZZ_MP 15865953 5848673 Elapsed: 00:00:00.00 14:13:00 SQL> lock table index_rebuild in EXCLUSIVE mode WAIT 120; Table(s) Locked. Elapsed: 00:00:00.00 14:13:00 SQL> DECLARE 14:13:00 2 l_sql varchar2(1000); 14:13:00 3 l_ct number; 14:13:00 4 BEGIN 14:13:00 5 FOR d in ( 14:13:00 6 select TABLE_OWNER, TABLE_NAME, INDEX_NAME, LEAF_BLOCKS from index_rebuild order by leaf_blocks asc 14:13:00 7 ) 14:13:00 8 LOOP 14:13:00 9 select count(*) into l_ct 14:13:00 10 from v$locked_object a, v$session b, dba_objects c 14:13:00 11 where b.sid = a.session_id 14:13:00 12 and a.object_id = c.object_id 14:13:00 13 and c.object_type='TABLE' 14:13:00 14 and c.owner=d.TABLE_OWNER 14:13:00 15 and c.object_name=d.TABLE_NAME; 14:13:00 16 IF l_ct = 0 THEN 14:13:00 17 dbms_output.put_line( '-- Check lock for owner|table|index : ' ||d.TABLE_OWNER||'.'||d.TABLE_NAME||'.'||d.INDEX_NAME||'='||l_ct ); 14:13:00 18 l_sql := 'alter index '||d.TABLE_OWNER||'.'||d.INDEX_NAME||' rebuild online parallel 4'; 14:13:00 19 dbms_output.put_line (l_sql); 14:13:00 20 execute immediate l_sql; 14:13:00 21 delete from index_rebuild where TABLE_OWNER=d.TABLE_OWNER and TABLE_NAME=d.TABLE_NAME and INDEX_NAME=d.INDEX_NAME; 14:13:00 22 END IF; 14:13:00 23 END LOOP; 14:13:00 24 END; 14:13:00 25 / -- Check lock for owner|table|index : XXXX.YYYYYYYYYY1.ZZZZZZZZZZZ_M=0 alter index XXXX.ZZZZZZZZZZZ_M rebuild online parallel 4 -- Check lock for owner|table|index : XXXX.YYYYYYYYYY2.ZZZZZZZZZZZ_MP=0 alter index XXXX.ZZZZZZZZZZZ_MP rebuild online parallel 4 PL/SQL procedure successfully completed. Elapsed: 04:00:23.08 18:13:23 SQL> commit; Commit complete. Elapsed: 00:00:00.01 18:13:23 SQL> exit
7. Run index_est_proc_2.sql.org (screen output only) or index_est_proc_2.sql (screen output and insert into index_rebuild table) to determine if any more indexes are listed for rebuild.
Note: The first rebuild contained a few dozen of indexes for rebuild but was not automated.
Later, there were only 2 indexes for rebuild as shown above from real production environment before minor improvements, e.g. — Display current user session info.
Q.E.D.