---------------------------------------------------------------------------------------- -- -- File name: cs_index_usage.sql -- -- Purpose: Index Usage (is an index still in use?) -- -- Author: Carlos Sierra -- -- Version: 2023/01/09 -- -- Usage: Execute connected to PDB -- -- Enter owner, table and index -- -- Example: $ sqlplus / as sysdba -- SQL> @cs_index_usage.sql -- -- Notes: Developed and tested on 12.1.0.2. -- --------------------------------------------------------------------------------------- -- @@cs_internal/cs_primary.sql @@cs_internal/cs_cdb_warn.sql @@cs_internal/cs_set.sql @@cs_internal/cs_def.sql @@cs_internal/cs_file_prefix.sql -- DEF cs_script_name = 'cs_index_usage'; -- COL username FOR A30; SELECT username FROM dba_users WHERE oracle_maintained = 'N' AND common = 'NO' ORDER BY username / PRO PRO 1. Table Owner: DEF table_owner = '&1.'; UNDEF 1; COL p_owner NEW_V p_owner FOR A30 NOPRI; SELECT username AS p_owner FROM dba_users WHERE oracle_maintained = 'N' AND common = 'NO' AND username = UPPER(TRIM('&&table_owner.')) AND ROWNUM = 1 / -- COL table_name FOR A30; SELECT table_name, blocks, num_rows FROM dba_tables WHERE owner = '&&p_owner.' ORDER BY table_name / PRO PRO 2. Table Name: DEF table_name = '&2.'; UNDEF 2; COL p_table_name NEW_V p_table_name NOPRI; SELECT table_name AS p_table_name FROM dba_tables WHERE owner = '&&p_owner.' AND table_name = UPPER(TRIM('&&table_name.')) AND ROWNUM = 1 / -- COL index_name FOR A30; SELECT index_name, leaf_blocks FROM dba_indexes WHERE owner = '&&p_owner.' AND table_name = '&&p_table_name.' ORDER BY index_name / PRO PRO 3. Index Name: DEF index_name = '&3.' UNDEF 3; DEF p_index_name = ''; COL p_index_name NEW_V p_index_name NOPRI; SELECT index_name AS p_index_name FROM dba_indexes WHERE owner = '&&p_owner.' AND table_name = '&&p_table_name.' AND index_name = UPPER(TRIM('&&index_name.')) AND ROWNUM = 1 / -- SELECT '&&cs_file_prefix._&&cs_script_name._&&p_owner..&&p_table_name..&&p_index_name.' cs_file_name FROM DUAL; -- @@cs_internal/cs_spool_head.sql PRO SQL> @&&cs_script_name..sql "&&p_owner." "&&p_table_name." "&&p_index_name." @@cs_internal/cs_spool_id.sql -- PRO TABLE_OWNER : "&&p_owner." PRO TABLE_NAME : "&&p_table_name." PRO INDEX_NAME : "&&p_index_name." -- COL index_name FOR A30; COL plan_hash_value FOR 999999999999999; COL executions FOR 999,999,999,990; COL elapsed_seconds FOR 999,999,990; COL cpu_seconds FOR 999,999,990; COL sql_text FOR A100 TRUNC; BREAK ON REPORT; COMPUTE SUM LABEL "TOTAL" OF executions elapsed_seconds cpu_seconds ON REPORT; PRO PRO v$object_dependency -> v$sql PRO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SELECT d.to_name AS index_name, s.sql_id, s.plan_hash_value, s.sql_text, s.executions, s.elapsed_seconds, s.cpu_seconds, s.last_active_time FROM ( SELECT d.to_name, d.from_hash, d.from_address FROM v$object_dependency d, v$db_object_cache c WHERE d.to_owner = '&&p_owner.' AND d.to_name = NVL('&&p_index_name.', d.to_name) --AND d.to_type = 70 -- MULTI-VERSIONED OBJECT AND d.to_name IN (SELECT index_name FROM dba_indexes WHERE owner = '&&p_owner.' AND table_name = '&&p_table_name.') AND c.hash_value = d.to_hash AND c.addr = d.to_address AND c.type = 'MULTI-VERSIONED OBJECT' GROUP BY d.to_name, d.from_hash, d.from_address ) d CROSS APPLY ( SELECT s.sql_id, s.sql_text, s.plan_hash_value, SUM(s.executions) AS executions, ROUND(SUM(s.elapsed_time)/POWER(10, 6)) AS elapsed_seconds, ROUND(SUM(s.cpu_time)/POWER(10, 6)) AS cpu_seconds, MAX(s.last_active_time) AS last_active_time FROM v$sql s WHERE s.hash_value = d.from_hash AND s.address = d.from_address -- AND s.parsing_user_id <> 0 -- AND s.parsing_schema_id <> 0 GROUP BY s.sql_id, s.sql_text, s.plan_hash_value ) s ORDER BY d.to_name, s.sql_id, s.plan_hash_value / PRO PRO v$sql_plan -> v$sql PRO ~~~~~~~~~~~~~~~~~~~ SELECT p.object_name AS index_name, p.sql_id, p.plan_hash_value, s.sql_text, s.executions, s.elapsed_seconds, s.cpu_seconds, s.last_active_time FROM ( SELECT p.object_name, p.sql_id, p.plan_hash_value FROM v$sql_plan p WHERE p.object_owner = '&&p_owner.' AND p.object_name = NVL('&&p_index_name.', p.object_name) AND p.object_type LIKE '%INDEX%' AND p.object_name IN (SELECT index_name FROM dba_indexes WHERE owner = '&&p_owner.' AND table_name = '&&p_table_name.') GROUP BY p.object_name, p.sql_id, p.plan_hash_value ) p CROSS APPLY ( SELECT MAX(s.sql_text) AS sql_text, SUM(s.executions) AS executions, ROUND(SUM(s.elapsed_time)/POWER(10, 6)) AS elapsed_seconds, ROUND(SUM(s.cpu_time)/POWER(10, 6)) AS cpu_seconds, MAX(s.last_active_time) AS last_active_time FROM v$sql s WHERE s.sql_id = p.sql_id AND s.plan_hash_value = p.plan_hash_value -- AND s.parsing_user_id <> 0 -- AND s.parsing_schema_id <> 0 ) s ORDER BY p.object_name, s.sql_id, s.plan_hash_value / PRO PRO dba_hist_sql_plan -> dba_hist_sqltext PRO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SELECT p.object_name AS index_name, p.sql_id, p.plan_hash_value, s.sql_text, p.timestamp FROM ( SELECT p.object_name, p.sql_id, p.plan_hash_value, MAX(timestamp) AS timestamp FROM dba_hist_sql_plan p WHERE p.object_owner = '&&p_owner.' AND p.object_name = NVL('&&p_index_name.', p.object_name) AND p.object_type LIKE '%INDEX%' AND p.dbid = TO_NUMBER('&&cs_dbid.') AND p.object_name IN (SELECT index_name FROM dba_indexes WHERE owner = '&&p_owner.' AND table_name = '&&p_table_name.') GROUP BY p.object_name, p.sql_id, p.plan_hash_value ) p CROSS APPLY ( SELECT MAX(DBMS_LOB.SUBSTR(s.sql_text, 1000)) AS sql_text FROM dba_hist_sqltext s WHERE s.sql_id = p.sql_id ) s ORDER BY p.object_name, p.sql_id, p.plan_hash_value / -- PRO PRO SQL> @&&cs_script_name..sql "&&p_owner." "&&p_table_name." "&&p_index_name." -- @@cs_internal/cs_spool_tail.sql @@cs_internal/cs_undef.sql @@cs_internal/cs_reset.sql --