Re: Mystique: Locks, Constraints and Indexes

From: Bradley W Howerter <howerter_at_world.std.com>
Date: Wed, 8 Mar 1995 21:45:31 GMT
Message-ID: <D555rv.E00_at_world.std.com>


Pauli Salmu <p.salmu_at_mn.medstroms.se> writes:

>We were getting strange deadlocks in our production DB and finally
>happened to discover that they had something to do with constraints.
>Then we got some help from the local Oracle representatives who said
>that you probably must index every column that has a foreign key
>constraint.

Here is an oraperl script that warns you if you have a foreign key constraint, but no index exists for the columns being constrained: (The man page follows the script)

#!/usr/local/bin/oraperl
($progname) = ($0 =~ m!([^/]*$)! ) ;
require "getopts.pl" ;

sub usage {

   print STDERR "$usage\n" ;
   exit 1;
}

$usage="Usage: $progname [-fcivh] [-t table_name] [-u username/password] owner" ;

&usage unless &Getopts('fchvit:u:');

&usage unless $owner = shift _at_ARGV ; $owner="\U$owner"; # CONVERT TO UPPERCASE

&usage if shift _at_ARGV;

# And now for some oraperl stuff

sub out_and_die {
   $ora_error=$ora_errstr ;
   &ora_close($csr);
   &ora_logoff($lda) ;

   die "_at__ $ora_error" ;
}

if ($opt_u) {

   ($uid,$upass)=split('/',$opt_u,2);
   if (! $upass) {

      system 'stty', '-echo';
      print STDERR "Enter password for $uid: ";
      chop($upass = <>);
      print STDERR " Thank you.\n";
      system 'stty', 'echo';

   }
}

$ora_cache=20000;

$lda = &ora_login('',$uid || '/',$upass) || die "Cannot log in\n$ora_errstr" ;

$table_clause=($opt_t?" and table_name = '\U$opt_t'":"");

$csr = &ora_open($lda,<<

   select constraint_name,table_name,decode (constraint_type,'P','PRIMARY','U','
UNIQUE','R','FOREIGN','V','CHECK_OPT','C','CHECK',constraint_type) , r_constrain
t_name , search_condition, delete_rule, status from dba_constraints

   where owner = '$owner' $table_clause
   order by 2,3 desc

   ) || &out_and_die("Line",__LINE__) ;

$csr_cols = &ora_open($lda,<<

   select constraint_name,table_name,column_name,position from dba_cons_columns    where owner = '$owner'

   ) || &out_and_die("Line",__LINE__);

write if $opt_h;

if ($opt_f || $opt_i) {

   $csr_ind = &ora_open($lda,<<
   select index_name,table_name, column_name,column_position from dba_ind_column s where table_owner = '$owner' $table_clause order by table_name,index_name,colu mn_position

   ) || &out_and_die("Line",__LINE__);

   while (($iname,$tname,$cname,$cpos) = &ora_fetch($csr_ind)) {

      $index{$tname,$cpos,$cname}.="$iname,";
      if ($opt_i) {
         if ($oiname ne $iname) {
            print "\n" if $not_first++;
            print "\n" if $not_first_also++ && $otname ne $tname;
            print "*TABLE*:   $tname\n" if $opt_v || $otname ne $tname;
            print "INDEX:     $iname\n";
            $oiname = $iname;
            $otname = $tname;
         }
         print "COLUMN:    $cpos $cname\n";
      }

   }
   &out_and_die("Line",__LINE__) unless $ora_errno == 0;    &ora_close($csr_ind);
   print "\n\nCONSTRAINT SECTION ******\n\n" if $opt_i; }

while (($name,$table,$column,$pos) = &ora_fetch($csr_cols)) {

   # I no longer think the .= is neccessary, but I'll leave it    $columns{$name,$pos} .= "$table:$column"; }
&out_and_die("Line",__LINE__) unless $ora_errno == 0; &ora_close($csr_cols) ;

while (($name,$table,$type,$r_name,$search,$rule,$status) = &ora_fetch($csr)) {

   next if $type eq 'CHECK' && !$opt_c;
   if ($otable ne $table) {

      print "\n" if $otable;
      print "*TABLE*:    $table\n";
      $otable=$table;

   }
   else {

      print "*TABLE*: $table\n" if $opt_v;    }

   print "CONSTRAINT: $name\n";
   print "TYPE:       $type\n";
   print "CHECK_COND: $search\n" if $search && $opt_c;
   print "RULE:       $rule\n" if $rule =~ /cascade/i;
   print "STATUS:     $status\n" if $status !~ /enabled/i;
   $index=1;
   if ($r_name) {
      print "REF_INDEX:  $r_name\n";
      while ($columns{$r_name,$index}) {
         ($rtable,$rcolumn)=split(/:/,$columns{$r_name,$index});
         print "RTABLE:     $rtable\n" unless $index > 1;
         print "RCOLUMN:    $index $rcolumn\n";
         ($table,$column)=split(/:/,$columns{$name,$index});
         print "COLUMN:     $index $column\n";
         if ($opt_f) {
            (_at_indexes)=split(/,/,$index{$table,$index,$column});
            if ($index == 1) {
               _at_intersection=_at_indexes;
            }
            else {
               local(%mark);
               grep($mark{$_}++,_at_indexes);
               _at_intersection=grep($mark{$_},_at_intersection);
            }
         }
         $index++;
      }
      # There should be an index for this foreign key
      # Find it and display it's name
      if ($opt_f) {
         if (_at_intersection) {
            for $index (_at_intersection) {
               print "FK_INDEX:   $index\n";
            }
         }
         else {
            print "********:  WARNING- NO FK_INDEX FOUND *****\n";
         }
      }

   }
   else {
      while ($columns{$name,$index}) {
         ($table,$column)=split(/:/,$columns{$name,$index});
         print "COLUMN:     $index $column\n";
         $index++;
      }

   }
 print "\n";
}
&out_and_die("Line",__LINE__) unless $ora_errno == 0; &ora_close($csr) ;

&ora_logoff($lda) ;

format top =

_at_<<<<<<                     CONSTRAINT REPORT         @>>>>>>>>>>>>>>>>>>
$ENV{'ORACLE_SID'},                                `/bin/date`
OWNER=_at_<<<<<<<<<<<<<<<<<<<<<<<<<<

$owner
.
format =

.

.TH consl 1WG "WGC Applications"
.SH NAME
consl \- Displays constraint info

.SH SYNOPSIS
.B "consl [-fihcv] [-t table_name] [-u username[/password]] schema"
.br
.SH DESCRIPTION

consl displays a schema's constraints, including the columns doing the constraining and the columns being constrained, and the tables being referenced.

Use -t to limit the output to a specific table.

Use -f to show the foreign key index on the constrained table. With this option, a warning is printed if there is no foreign key index.

The -h (header) option prints a header one time only.

The -v (verbose) option prints the table for each constraint instead of just printing it once for all the table's constraints.

The -i (index) option prints the indexes and their columns prior to printing the constraint report. Look for CONSTRAINT SECTION*** to find the constraints.

The -c (check) option prints check constraint information.

The -u option logs you into oracle with the specified username. The password, if not supplied, will be prompted for invisibly. If no -u, the '/' is the username used.

The schema is the oracle account on which you would like information. It is required.
.SH SEE_ALSO
cons(1wg)
.SH AUTHOR
Brad Howerter, bhower_at_wgc.woodward.com Received on Wed Mar 08 1995 - 22:45:31 CET

Original text of this message