Indexes in Oracle - An Introduction

If an index has been established and the SQL statement is setup to take advantage of the index, the index will be searched first and the access time will probably be noticeably lower if you are dealing with a large database. Without an index Oracle does a full table search examining every row. Oracle is actively involved in using indexes to satisfy queries and examines the query to determine what indexes it will use.

In Oracle, indexes are grouped with the concept of constraints. There are two major categories of constraints: integrity constraints that refer to the key fields and value constraints that deal with data entered into a column. A constraint is used to protect the validity of data in one or multiple tables and prevent invalid entries. Specifically, constraints enforce certain rules dealing with a table or a column of that table and can be used to prevent the deletion of a table that has children or dependencies. Indexes as constraints are making sure that the primary key field is unique and that the connection through a foreign key is valid.

The constraints that we will look at are shown in the table below.

ConstraintProcessing
CHECKAllows the specification of a condition on the data
FOREIGN KEYKey used in the relationship of two tables
PRIMARY KEYUnique key to each row in the table - uniquely identifies row
NOT NULLColumn must not be null
UNIQUEColumn(s) that must be unique for each row in the table


When the programmer is using constraints, they have the option of naming them (then the name can be meaningful) or having the system generate a name with the SYS-Cn format. Constraints can be part of the process to create a table or they can be done as maintenance of the table. Since constrains can be on a column or on a table they can be defined at either level. If you want to see the constraints that have been assigned to a particular table do a SELECT from the USER_CONSTRAINTS data dictionary table.

To see all tables use:

SELECT * FROM USER_CONSTRAINTS;

To see a specific table, use:

SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'DONOR';

In the example below, I have defined one field as a primary key and put a check constraint on another.

SQL CODE:

1  CREATE TABLE TRYKEY1
2  (idno NUMBER(3) CONSTRAINT idno_pk PRIMARY KEY,
3  name VARCHAR2(20),
4* deptno NUMBER(2) CONSTRAINT valid_dept_ch CHECK (deptno > 0 AND deptno < 20))
SQL> /

Table created.

I am now inserting data into the table and making some errors to correspond to the constraints that I put in the table. The first row was inserted with no problems. In the second example, I tried to put in a row with a duplicate of the idno in the first row. An error occurred because of idno_pk. In the next example, I violated the deptno check and got an error on that constraint entitled valid_dept_ch. Notice that when I do a DESC on the table, the idno is described as NOT NULL. This is because a primary key can not contain a null value.

SQL CODE:

SQL> INSERT INTO TRYKEY1
  2  VALUES(111,'Susan Smith',12);

1 row created.

SQL> INSERT INTO TRYKEY1
  2  VALUES (111, 'David Johnson',10);
VALUES (111, 'David Johnson',10)
    *
ERROR at line 2:
ORA-00001: unique constraint (SCOTT.IDNO_PK) violated

SQL> INSERT INTO TRYKEY1
  2  VALUES (222, 'Josh Anderson',24);
VALUES (222, 'Josh Anderson',24)
    *
ERROR at line 2:
ORA-02290: check constraint (SCOTT.VALID_DEPT_CH) violated


SQL> SELECT * FROM trykey1;

     IDNO NAME                    DEPTNO
--------- -------------------- ---------
      111 Susan Smith                 12

SQL> DESC trykey1;
 Name                            Null?    Type
 ------------------------------- -------- ----
 IDNO                            NOT NULL NUMBER(3)
 NAME                                     VARCHAR2(20)
 DEPTNO                                   NUMBER(2)

In the examples below, I created a second table with the deptno as the primary key and the deptname as a field that must be unique. I successfully inserted the first row and then tried to violate the unique key principle in the second insert and got an error.

SQL CODE:

1  CREATE TABLE trykeysnc
  2  (deptno NUMBER(2) CONSTRAINT deptnosnd_pk PRIMARY KEY,
  3* deptname VARCHAR(20) CONSTRAINT deptname_uk UNIQUE)
SQL> /

Table created.

SQL> INSERT INTO trykeysnc
  2  VALUES(12,'Information Systems');

1 row created.

SQL> INSERT INTO trykeysnc
  2  VALUES(14,'Information Systems');
INSERT INTO trykeysnc
            *
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.DEPTNAME_UK) violated

In the example below, I created a new table called trykey2 that has idno as the primary key and deptno as a foreign key that references into the deptno on the table trykeysnc. When I tried to put a record in the trykey2 table that did not match a deptno in the trykeysnc table I got a violation error because the parent key was not found. In otherwords, there was no prime key for a dept 15 in the trykeysnc table so I could not put in this foreign key.

SQL CODE:

1  CREATE TABLE trykey2
  2  (idno NUMBER(3) constraint idnotry2_pk PRIMARY KEY,
  3  name VARCHAR2(20),
  4* deptno NUMBER(2) constraint deptnotry2_fk REFERENCES trykeysnc(deptno))
SQL> /

Table created.

SQL> SELECT * FROM trykeysnc;

   DEPTNO DEPTNAME
--------- --------------------
       12 Information Systems

SQL> INSERT INTO trykey2
  2  VALUES(111, 'Gary Tyler', 15);
INSERT INTO trykey2
            *
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.DEPTNOTRY2_FK) violated - parent key not found


SQL> INSERT into trykey2
  2  VALUES (111, 'Gary Tyler', 12);

1 row created.

SQL> SELECT * FROM trykey2;

     IDNO NAME                    DEPTNO
--------- -------------------- ---------
      111 Gary Tyler                  12

In this example, I tried to alter the trykey2 table by adding a field called paycode that could not be null. I could not do this because the table already had rows in it and a table must be empty to add a mandatory NOT NULL column.

SQL CODE:

1  ALTER TABLE TRYKEY2
  2* ADD (paycode CHAR(2) CONSTRAINT paycode_nn NOT NULL)
SQL> /
ALTER TABLE TRYKEY2
            *
ERROR at line 1:
ORA-01758: table must be empty to add mandatory (NOT NULL) column

SQL> DELETE * FROM trykey2;
DELETE * FROM trykey2
       *
ERROR at line 1:
ORA-00903: invalid table name


SQL> DELETE FROM trykey2;

1 row deleted.

SQL> SELECT * FROM trykey2;

no rows selected

SQL> ALTER TABLE trykey2
  2  ADD (paycode CHAR(2) CONSTRAINT paycode2_nn NOT NULL);

Table altered.

SQL> DESC trykey2;
 Name                            Null?    Type
 ------------------------------- -------- ----
 IDNO                            NOT NULL NUMBER(3)
 NAME                                     VARCHAR2(20)
 DEPTNO                                   NUMBER(2)
 PAYCODE                         NOT NULL CHAR(2)

SQL> INSERT INTO trykey2 (idno, name, deptno)
  2  VALUES (111, 'John Doe', 12);
INSERT INTO trykey2 (idno, name, deptno)
            *
 
ERROR at line 1:
ORA-01400: mandatory (NOT NULL) column is missing or NULL during insert

I have created a table named nameadr1 that has no indexes. Now I want to index the table so I am creating three indexes. One on idno_na, one on last_na and first_na and another on salary_na descending. This is done with CREATE INDEX. If you decide you do not want an index, you can drop it with DROP INDEX.

SQL CODE:


SQL> CREATE TABLE nameadr1
  2  (idno_na NUMBER(3),
  3  last_na VARCHAR2(12),
  4  first_na VARCHAR2(10),
  5  salary_na NUMBER(8,2),
  6  npaycode NUMBER(2));

Table created.

SQL> DESC nameadr1;
 Name                            Null?    Type
 ------------------------------- -------- ----
 IDNO_NA                                  NUMBER(3)
 LAST_NA                                  VARCHAR2(12)
 FIRST_NA                                 VARCHAR2(10)
 SALARY_NA                                NUMBER(8,2)
 NPAYCODE                                 NUMBER(2)

SQL> CREATE INDEX idno_index ON nameadr1(idno_na);

Index created.

1* CREATE INDEX name_index ON nameadr1(last_na,first_na)
SQL> /

Index created.

SQL> CREATE INDEX sal_index ON nameadr1(salary_na desc);

Index created.

SQL> DROP INDEX idno_index;

Index dropped.

Now that I dropped the ordinary index on idno, I am going to make it the primary key. This is done with the ALTER and the command ADD PRIMARY KEY with the key in parenthesis. If you want to add a foreign key, it is also done with the ALTER. First, I tried to create the foreign key without creating the table that I needed to relate into. Because I must reference the secondary table in the creation of the foreign key, Oracle was aware that the secondary table did not exist and denyed the request. I then created the secondary table without giving it a primary key, used the ALTER to make the primary key and then went back to the main table and created the FOREIGN KEY.

SQL CODE:


SQL> ALTER TABLE nameadr1
  2  ADD PRIMARY KEY(idno_na);

Table altered.

SQL> DESC nameadr1;
 Name                            Null?    Type
 ------------------------------- -------- ----
 IDNO_NA                         NOT NULL NUMBER(3)
 LAST_NA                                  VARCHAR2(12)
 FIRST_NA                                 VARCHAR2(10)
 SALARY_NA                                NUMBER(8,2)
 NPAYCODE                                 NUMBER(2)

SQL> ALTER TABLE nameadr1
  2  ADD FOREIGN KEY (npaycode) REFERENCES pay1;
ADD FOREIGN KEY (npaycode) REFERENCES pay1
                                      *
ERROR at line 2:
ORA-00942: table or view does not exist


SQL> CREATE TABLE pay1
  2  (paycode NUMBER(2), jobname VARCHAR2(15));

Table created.

SQL> DESC pay1;
 Name                            Null?    Type
 ------------------------------- -------- ----
 PAYCODE                                  NUMBER(2)
 JOBNAME                                  VARCHAR2(15)

SQL> ALTER TABLE pay1
  2  ADD PRIMARY KEY (paycode);

Table altered.

SQL> ALTER TABLE nameadr1
  2  ADD FOREIGN KEY (npaycode) REFERENCES pay1;

Table altered.