Oracle Foreign Key Constraints with missing indexes
Thomas Gutzmann from Tom Kyte script to identify foreign key constraints with missing indexes works in only one schema.
I had the problem of having two tightly integrated schemas with referential constraints going back and forth.
The below version of their script handles multiple schemas.
It also displays the size of the tables involved, because there can be a case for leaving FK indexes off for very large tables unless/until needed.
Missing FK indexes are a common cause of enqueue lock waits.
WITH cons AS ( SELECT c.owner , c.table_name , c.constraint_name , c.r_owner , MAX ( CASE cc.position WHEN 1 THEN cc.column_name END ) AS cname1 , MAX ( CASE cc.position WHEN 2 THEN cc.column_name END ) AS cname2 , MAX ( CASE cc.position WHEN 3 THEN cc.column_name END ) AS cname3 , MAX ( CASE cc.position WHEN 4 THEN cc.column_name END ) AS cname4 , MAX ( CASE cc.position WHEN 5 THEN cc.column_name END ) AS cname5 , MAX ( CASE cc.position WHEN 6 THEN cc.column_name END ) AS cname6 , MAX ( CASE cc.position WHEN 7 THEN cc.column_name END ) AS cname7 , MAX ( CASE cc.position WHEN 8 THEN cc.column_name END ) AS cname8 , COUNT(*) AS col_cnt FROM dba_constraints c JOIN dba_cons_columns cc ON cc.constraint_name = c.constraint_name AND cc.owner = c.owner WHERE c.constraint_type = 'R' AND cc.owner IN ( 'MYSCHEMA1' , 'MYSCHEMA2' ) GROUP BY c.table_name , c.constraint_name , c.owner , c.r_owner ) , inds AS ( SELECT cons.owner , cons.table_name , cons.constraint_name , cons.r_owner , LOWER ( cons.cname1 || NVL2 ( cons.cname2 , ',' || cons.cname2 , NULL ) || NVL2 ( cons.cname3 , ',' || cons.cname3 , NULL ) || NVL2 ( cname4 , ',' || cname4 , NULL ) || NVL2 ( cons.cname5 , ',' || cons.cname5 , NULL ) || NVL2 ( cname6 , ',' || cname6 , NULL ) || NVL2 ( cons.cname7 , ',' || cons.cname7 , NULL ) || NVL2 ( cname8 , ',' || cname8 , NULL ) ) AS column_list FROM cons WHERE cons.col_cnt > ALL ( SELECT COUNT(*) FROM dba_ind_columns ic WHERE ic.table_name = cons.table_name AND ic.table_owner = cons.owner AND ic.column_name IN ( cons.cname1 , cons.cname2 , cons.cname3 , cons.cname4 , cons.cname5 , cons.cname6 , cons.cname7 , cons.cname8 ) AND ic.column_position <= cons.col_cnt GROUP BY ic.index_name ) ) SELECT LOWER ( inds.owner ) , LOWER ( inds.table_name ) , t.num_rows , t.blocks * 8/1024/1024 AS gb , LOWER ( inds.r_owner ) , 'CREATE INDEX ' || LOWER ( inds.owner ) || '.' || LOWER ( inds.constraint_name ) || ' ON ' || LOWER ( inds.owner ) || '.' || LOWER ( inds.table_name ) || ' ( ' || inds.column_list || ' ) TABLESPACE ;' AS ddl_statement FROM inds JOIN dba_tables t ON t.table_name = inds.table_name AND t.owner = inds.owner ORDER BY inds.owner , inds.table_name , inds.r_owner , inds.constraint_name ;
Hello Andrew,
Greetings !!
It’s really best script which has developed by you !!
This script is reducing lot of efforts, Really nice one , thanks a lot !!
Best Regards,
Yogesh D Jawale