Index Skip Scan in Oracle

With Oracle 9i, the Cost-Based Optimizer (CBO) is equipped with many useful features, one of them is “Index skip scan“. In previous releases a composite index could only be used if the first column, the leading edge, of the index was referenced in the WHERE clause of a statement. In Oracle 9i this restriction is removed because the optimizer can perform skip scans to retrieve rowids for values that do not use the prefix. This means even if you have a composite index on more than one column and you use the non-prefix column alone in your SQL, it may still use index. (Earlier I use to think that it will not use index :)) Its not always guaranteed that the Index Skip Scan will be used, this is because Cost-Based Optimizer (CBO) will calculate the cost of using the index and if it is more than that of full table scan, then it may not use index. This approach is advantageous because:

  • It reduces the number of indexes needed to support a range of queries. This increases performance by reducing index maintenance and decreases wasted space associated with multiple indexes.
  • The prefix column should be the most discriminating and the most widely used in queries. These two conditions do not always go hand in hand which makes the decision difficult. In these situations skip scanning reduces the impact of making the “wrong” decision.

Index skip scan works differently from a normal index (range) scan. A normal range scan works from top to bottom first and then move horizontal. But a Skip scan includes several range scans in it. Since the query lacks the leading column it will rewrite the query into smaller queries and each doing a range scan. Consider following example where we create a test table and create index on first two columns a and b. Also we put some dummy data inside test table. See how Index is getting selected when we execute select statement with column b in where clause.

Step 1:

CREATE TABLE test (a NUMBER, b NUMBER, c NUMBER);
Code language: SQL (Structured Query Language) (sql)

Table created.

Step 2:

CREATE INDEX test_i ON test (a, b);
Code language: SQL (Structured Query Language) (sql)

Index created.

Step 3:

BEGIN FOR i IN 1 .. 100000 LOOP INSERT INTO test VALUES (MOD (i, 5), i, 100); END LOOP; COMMIT; END; /
Code language: SQL (Structured Query Language) (sql)

PL/SQL procedure successfully completed.

Step 4:

exec dbms_stats.gather_table_stats ( ownname => 'gauravsoni', tabname => 'test', cascade => true );
Code language: SQL (Structured Query Language) (sql)

PL/SQL procedure successfully completed.

Step 5:

set autotrace trace exp
Code language: SQL (Structured Query Language) (sql)

Step 6:

SELECT * FROM test WHERE b = 95267;
Code language: SQL (Structured Query Language) (sql)

Execution Plan

0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=22 Card=1 Bytes=10) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (TABLE) (Cost=22 Card=1 Bytes=10) 2 1 INDEX (SKIP SCAN) OF 'TEST_I' (INDEX) (Cost=21 Card=1)
Code language: SQL (Structured Query Language) (sql)

I above example, "select * from test where b=95267" was broken down to several small range scan queries. It was effectively equivalent to following:

SELECT * FROM test WHERE a = 0 AND b = 95267 UNION SELECT * FROM test WHERE a = 1 AND b = 95267 UNION SELECT * FROM test WHERE a = 2 AND b = 95267 UNION SELECT * FROM test WHERE a = 3 AND b = 95267 UNION SELECT * FROM test WHERE a = 4 AND b = 95267;
Code language: SQL (Structured Query Language) (sql)

In concrete, saying that skip scan is not as efficient as normal “single range scan” is correct. But yet saves some disk space and overhead of maintaining another index.

Reference

Oracle Documentation on Index Skip Scan

View Comments

  • Good Article. The usage of index skip scan depends on the cardinality of the leading column. When the cardinality is low, means there are few distinct values in the leading column, index skip scan comes into effect. However as you have described it is not much efficient compared to other index scans like range scan.

Share
Published by
Gaurav Soni
Tags: database indexes Oracle oracle-11g

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

5 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

5 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

5 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

5 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

5 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

5 years ago