Page Content

Tutorials

How to create Indexes in Oracle? With Examples

Indexes in Oracle

An optionally constructed database item, a database index is mostly used to improve query performance. The idea behind an index is the same as that of the index at the back of a real book: it links a search word or column value to the location of the relevant data.

An index in a database holds the value of a column and its Row Identifier (ROWID). By providing a shortcut that contains the actual location of the table row on the disc, the ROWID enables Oracle to efficiently retrieve table data with the fewest possible disc reads. Without an index, Oracle could have to read every row in the table in order to fulfil a query, which is known as a full-table scan.

While indexes significantly enhance the speed of SELECT statements, particularly those involving WHERE clauses, joins, ORDER BY clauses, or MAX/MIN functions, they are not without cost. Indexes consume disk space. Every Data Manipulation Language (DML) operation (INSERT, UPDATE, or DELETE) performed on an indexed column requires the index itself to be updated, which slows down DML performance.

The B*-tree index is the most popular and default form of index that Oracle offers.

Create Table and Insert Example

Using SQL Data Definition Language (DDL) instructions, which are frequently the first step in object creation, create a simple table and populate it to illustrate different index types:

CREATE TABLE CUST (
  CUST_ID    NUMBER PRIMARY KEY,
  LAST_NAME  VARCHAR2(30),
  FIRST_NAME VARCHAR2(30),
  GENDER     VARCHAR2(6)
) TABLESPACE USERS;

This table is populated using the INSERT DML command:

INSERT INTO CUST VALUES(1,'SMITH','JOHN', 'M');
INSERT INTO CUST VALUES(2,'JONES','JANE', 'F');
INSERT INTO CUST VALUES(3,'BROWN','BOB', 'M');
INSERT INTO CUST VALUES(4,'BROWN','MARY', 'F');
COMMIT;
-- Output of SELECT statement
SELECT CUST_ID, LAST_NAME, FIRST_NAME, GENDER FROM CUST;
CUST_ID | LAST_NAME | FIRST_NAME | GENDER
--------|-----------|------------|--------
1       | SMITH     | JOHN       | M
2       | JONES     | JANE       | F
3       | BROWN     | BOB        | M
4       | BROWN     | MARY       | F

Create Index

An index can be manually created using the CREATE INDEX command. To enforce a PRIMARY KEY or UNIQUE constraint that has been defined on a table, Oracle automatically generates a unique index. If not, indexes need to be explicitly established with the CREATE INDEX statement.

The table name, the index name, the column(s) to be indexed, and the index type (optional) are all specified in the basic syntax:

CREATE INDEX CUST_IDX_LASTNAME ON CUST(LAST_NAME);

Additionally, you can incorporate options such as tablespace, which is often advised for improved availability and manageability, to physically isolate the index from the table:

CREATE INDEX CUST_IDX_FIRSTNAME ON CUST(FIRST_NAME) TABLES PACE CUST_INDEXES;

Drop Index

An index can be deleted from the database using the DROP INDEX statement. This DDL action cannot be undone; it is permanent. The index may become more difficult to manage in the future if it was dropped first if it was automatically generated to support a PRIMARY KEY or UNIQUE constraint.

DROP INDEX CUST_IDX_LASTNAME;

When an index is eliminated, the database no longer has to maintain the index structure, which lowers the overhead related to DML operations on the table.

Unique Index

One type of B*-tree index that is used to ensure that column values are unique is called a Unique Index. It ensures that none of the indexed columns in any two table rows have the same non-NULL value. A NULL value in the indexed column may appear in more than one row, though, because a unique index does not guarantee uniqueness for NULL values.

The UNIQUE keyword allows for the explicit creation of unique indexes:

CREATE UNIQUE INDEX CUST_UK1 ON CUST(FIRST_NAME, LAST_NAME);

An error notice will be returned by the database if a user does a DML operation later on that breaks this uniqueness rule:

INSERT INTO CUST VALUES(5,'BROWN','MARY', 'F');

-- Attempted Output (Failure):
ERROR at line 1: ORA-00001: unique constraint (CUST_UK1) violated

Function-based Index

An index that is based on a SQL function or expression applied to one or more columns is called a function-based index. These indexes are especially useful when the function or expression in the WHERE clause is used frequently in queries.

When a query applies a function (like UPPER()) to a column, the optimiser usually cannot use a standard index on that column. In order to rectify this and give the optimiser an access path, a function-based index is created.

If the last name is frequently converted to uppercase using the CUST table example:

CREATE INDEX UPPER_LASTNAME_IX ON CUST (UPPER(LAST_NAME));

This index makes it possible for the query optimiser to resolve statements such as these effectively:

SELECT * FROM CUST WHERE UPPER(LAST_NAME) = 'BROWN';

Bitmap Index

A bitmap index does not index each row individually; instead, it keeps the ROWIDs linked to a key value as a bitmap. Each bit in the bitmap that corresponds to each unique column value in the index shows whether or not a particular row has that key value (1 for presence, 0 for absence).

For columns with low cardinality that is, columns with few different values, like the GENDER column in our example (M or F) bitmap indexes are designed. When data is loaded in batches and updated infrequently, they are widely utilised in reporting or data warehouse settings.

For Online Transaction Processing (OLTP) systems with a large volume of INSERT/UPDATE/DELETE operations, bitmap indexes are crucially inappropriate. One index entry points to numerous rows, hence DML procedures may result in serious locking problems. You can’t make a bitmap index that is unique.

A bitmap index is created using the BITMAP keyword:

CREATE BITMAP INDEX CUST_BMX_GENDER ON CUST(GENDER);

The bitmap structure for GENDER (Male/Female) in the CUST table example would conceptually map rows using 1s and 0s, enabling queries using AND or OR operators on these low-cardinality columns to be swiftly resolved by evaluating the bitmaps. For example, the value ‘M’ is mapped to the ROWIDs for rows 1 and 3, and ‘F’ to rows 2 and 4, according to the index.

Index