0% found this document useful (0 votes)
2 views16 pages

Why Isn't Oracle Using My Index

The document discusses various reasons why Oracle might not use an index during query execution, such as small table size, low selectivity, function-based index issues, data skew, NULL values, implicit type conversion, OR conditions, CBO decisions, index invisibility, and parallel execution. It provides detailed demos for each scenario, explaining the underlying issues and offering solutions to ensure that Oracle utilizes indexes effectively. The conclusion emphasizes the importance of understanding these factors for optimizing query performance.

Uploaded by

quanwenzhao
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views16 pages

Why Isn't Oracle Using My Index

The document discusses various reasons why Oracle might not use an index during query execution, such as small table size, low selectivity, function-based index issues, data skew, NULL values, implicit type conversion, OR conditions, CBO decisions, index invisibility, and parallel execution. It provides detailed demos for each scenario, explaining the underlying issues and offering solutions to ensure that Oracle utilizes indexes effectively. The conclusion emphasizes the importance of understanding these factors for optimizing query performance.

Uploaded by

quanwenzhao
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

I wanna talking about "Why Oracle Isn't Using Index?

", please offer me plenty


of demos to explore it.

Certainly! Understanding why Oracle isn't using an index can be a complex


topic, as it involves various factors such as query structure, data distribution,
and database configuration. Below are several demos and scenarios to help
you explore this issue. These examples will illustrate common reasons why
Oracle might choose not to use an index.

Demo 1: Small Table Full Scan

Scenario: Oracle might choose a full table scan over an index scan if the
table is small.

sql
Copy
-- Create a small table
CREATE TABLE small_table (
id NUMBER PRIMARY KEY,
name VARCHAR2(50)
);

-- Insert a few rows


INSERT INTO small_table VALUES (1, 'Alice');
INSERT INTO small_table VALUES (2, 'Bob');
INSERT INTO small_table VALUES (3, 'Charlie');

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM small_table WHERE id = 2;

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: For small tables, Oracle might determine that a full table scan
is more efficient than using an index.

Demo 2: Low Selectivity Index

Scenario: If the index has low selectivity (i.e., it doesn't filter out many rows),
Oracle might skip it.
sql
Copy
-- Create a table with a low selectivity column
CREATE TABLE low_selectivity (
id NUMBER PRIMARY KEY,
status VARCHAR2(10)
);

-- Insert data with mostly the same status


BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO low_selectivity VALUES (i, 'ACTIVE');
END LOOP;
COMMIT;
END;
/

-- Create an index on the status column


CREATE INDEX idx_status ON low_selectivity(status);

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM low_selectivity WHERE status = 'ACTIVE';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Since almost all rows have the same status, the index
on status is not very selective, and Oracle might prefer a full table scan.

Demo 3: Function-Based Index Ignored

Scenario: If you use a function in the WHERE clause and don't have a
corresponding function-based index, Oracle might not use the index.

sql
Copy
-- Create a table
CREATE TABLE function_based (
id NUMBER PRIMARY KEY,
name VARCHAR2(50)
);
-- Insert data
BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO function_based VALUES (i, 'Name' || i);
END LOOP;
COMMIT;
END;
/

-- Create an index on the name column


CREATE INDEX idx_name ON function_based(name);

-- Query using a function


EXPLAIN PLAN FOR
SELECT * FROM function_based WHERE UPPER(name) = 'NAME500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Since the query uses UPPER(name), the existing index


on name won't be used. You would need a function-based index like CREATE
INDEX idx_upper_name ON function_based(UPPER(name));.

Demo 4: Index Skip Due to Data Skew

Scenario: If the data is highly skewed, Oracle might decide not to use the
index.

sql
Copy
-- Create a table with skewed data
CREATE TABLE skewed_data (
id NUMBER PRIMARY KEY,
category VARCHAR2(10)
);

-- Insert skewed data


BEGIN
FOR i IN 1..900 LOOP
INSERT INTO skewed_data VALUES (i, 'A');
END LOOP;
FOR i IN 901..1000 LOOP
INSERT INTO skewed_data VALUES (i, 'B');
END LOOP;
COMMIT;
END;
/

-- Create an index on the category column


CREATE INDEX idx_category ON skewed_data(category);

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM skewed_data WHERE category = 'B';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: If the data is highly skewed (e.g., most rows have category 'A'),
Oracle might decide that a full table scan is more efficient for certain queries.

Demo 5: Index Not Used Due to NULLs

Scenario: Indexes do not store NULL values, so queries searching for NULLs
won't use the index.

sql
Copy
-- Create a table with nullable column
CREATE TABLE nullable_column (
id NUMBER PRIMARY KEY,
data VARCHAR2(50)
);

-- Insert data with some NULLs


BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO nullable_column VALUES (i, CASE WHEN MOD(i, 2)
= 0 THEN 'Data' || i ELSE NULL END);
END LOOP;
COMMIT;
END;
/

-- Create an index on the data column


CREATE INDEX idx_data ON nullable_column(data);
-- Query for NULL values
EXPLAIN PLAN FOR
SELECT * FROM nullable_column WHERE data IS NULL;

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Since the index doesn't store NULL values, Oracle will perform a
full table scan to find rows where data IS NULL.

Demo 6: Index Not Used Due to Implicit Type

Conversion

Scenario: Implicit type conversion in the WHERE clause can prevent Oracle
from using the index.

sql
Copy
-- Create a table with a VARCHAR2 column
CREATE TABLE type_conversion (
id NUMBER PRIMARY KEY,
code VARCHAR2(10)
);

-- Insert data
BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO type_conversion VALUES (i, TO_CHAR(i));
END LOOP;
COMMIT;
END;
/

-- Create an index on the code column


CREATE INDEX idx_code ON type_conversion(code);

-- Query with implicit type conversion


EXPLAIN PLAN FOR
SELECT * FROM type_conversion WHERE code = 123;

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: The query implicitly converts code to a number, which prevents


Oracle from using the index on the code column.

Demo 7: Index Not Used Due to OR Condition

Scenario: Oracle might not use an index if the query contains an OR


condition that isn't optimized.

sql
Copy
-- Create a table
CREATE TABLE or_condition (
id NUMBER PRIMARY KEY,
col1 VARCHAR2(50),
col2 VARCHAR2(50)
);

-- Insert data
BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO or_condition VALUES (i, 'Data' || i, 'Info' || i);
END LOOP;
COMMIT;
END;
/

-- Create indexes on col1 and col2


CREATE INDEX idx_col1 ON or_condition(col1);
CREATE INDEX idx_col2 ON or_condition(col2);

-- Query with OR condition


EXPLAIN PLAN FOR
SELECT * FROM or_condition WHERE col1 = 'Data500' OR col2 =
'Info500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Oracle might not use the indexes on col1 and col2 due to the OR
condition, leading to a full table scan.
Demo 8: Index Not Used Due to CBO (Cost-Based

Optimizer) Decision

Scenario: The Cost-Based Optimizer (CBO) might decide that using the index
is not cost-effective.

sql
Copy
-- Create a large table
CREATE TABLE large_table (
id NUMBER PRIMARY KEY,
data VARCHAR2(100)
);

-- Insert a large amount of data


BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO large_table VALUES (i, 'Data' || i);
END LOOP;
COMMIT;
END;
/

-- Create an index on the data column


CREATE INDEX idx_data ON large_table(data);

-- Gather statistics
EXEC DBMS_STATS.GATHER_TABLE_STATS('YOUR_SCHEMA',
'large_table');

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM large_table WHERE data = 'Data50000';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: The CBO might decide that a full table scan is more efficient
than using the index, especially if the table statistics indicate that a large
portion of the table would need to be scanned.
Demo 9: Index Not Used Due to Index Invisibility

Scenario: If an index is set to invisible, Oracle won't use it.

sql
Copy
-- Create a table
CREATE TABLE invisible_index (
id NUMBER PRIMARY KEY,
data VARCHAR2(50)
);

-- Insert data
BEGIN
FOR i IN 1..1000 LOOP
INSERT INTO invisible_index VALUES (i, 'Data' || i);
END LOOP;
COMMIT;
END;
/

-- Create an index and set it to invisible


CREATE INDEX idx_data ON invisible_index(data);
ALTER INDEX idx_data INVISIBLE;

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM invisible_index WHERE data = 'Data500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Since the index is invisible, Oracle won't consider it for the
query, resulting in a full table scan.

Demo 10: Index Not Used Due to Parallel Execution

Scenario: Oracle might choose a full table scan when parallel execution is
enabled.

sql
Copy
-- Create a large table
CREATE TABLE parallel_table (
id NUMBER PRIMARY KEY,
data VARCHAR2(100)
);

-- Insert a large amount of data


BEGIN
FOR i IN 1..1000000 LOOP
INSERT INTO parallel_table VALUES (i, 'Data' || i);
END LOOP;
COMMIT;
END;
/

-- Create an index on the data column


CREATE INDEX idx_data ON parallel_table(data);

-- Enable parallel execution


ALTER TABLE parallel_table PARALLEL;

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM parallel_table WHERE data = 'Data500000';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Oracle might prefer a full table scan with parallel execution
over using the index, especially for large tables.

Conclusion

These demos illustrate various scenarios where Oracle might choose not to
use an index. The decision is often based on factors like table size, data
distribution, query structure, and database configuration. By understanding
these factors, you can better optimize your queries and indexes for
performance.
How to fix it in order to use index?

Fixing the issue to ensure Oracle uses an index depends on the specific
scenario. Below are solutions for each of the scenarios discussed earlier, along
with explanations and steps to make Oracle use the index effectively.

Demo 1: Small Table Full Scan

Issue: Oracle prefers a full table scan for small tables because it’s faster than
using an index.

Solution: If you still want Oracle to use the index (e.g., for testing or specific
use cases), you can use a hint to force index usage.

sql
Copy
-- Force Oracle to use the index
EXPLAIN PLAN FOR
SELECT /*+ INDEX(small_table) */ * FROM small_table WHERE id = 2;

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: The /*+ INDEX(table_name) */ hint forces Oracle to use the index.
However, this is not recommended for small tables unless you have a specific
reason.

Demo 2: Low Selectivity Index

Issue: The index is not selective enough (e.g., most rows have the same
value).

Solution: Create a more selective index or use a composite index.

sql
Copy
-- Drop the existing low-selectivity index
DROP INDEX idx_status;
-- Create a composite index on multiple columns
CREATE INDEX idx_status_id ON low_selectivity(status, id);

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM low_selectivity WHERE status = 'ACTIVE' AND id =
500;

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: A composite index on (status, id) increases selectivity, making it


more likely for Oracle to use the index.

Demo 3: Function-Based Index Ignored

Issue: Oracle ignores the index because the query uses a function on the
indexed column.

Solution: Create a function-based index to match the query.

sql
Copy
-- Drop the existing index
DROP INDEX idx_name;

-- Create a function-based index


CREATE INDEX idx_upper_name ON function_based(UPPER(name));

-- Query the table using the function


EXPLAIN PLAN FOR
SELECT * FROM function_based WHERE UPPER(name) = 'NAME500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: The function-based index matches the


query's UPPER(name) condition, allowing Oracle to use the index.
Demo 4: Index Skip Due to Data Skew

Issue: Oracle avoids the index because the data is highly skewed.

Solution: Use histograms to help Oracle understand the data distribution.

sql
Copy
-- Gather statistics with histograms
EXEC DBMS_STATS.GATHER_TABLE_STATS('YOUR_SCHEMA',
'skewed_data', METHOD_OPT => 'FOR ALL COLUMNS SIZE AUTO');

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM skewed_data WHERE category = 'B';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Histograms provide Oracle with more detailed statistics about


data distribution, helping it make better decisions about index usage.

Demo 5: Index Not Used Due to NULLs

Issue: Indexes do not store NULL values, so queries searching for NULLs
won't use the index.

Solution: Use a function-based index to include NULLs or rewrite the query.

sql
Copy
-- Create a function-based index to handle NULLs
CREATE INDEX idx_data_null ON nullable_column(NVL(data, 'NULL'));

-- Query the table using the function


EXPLAIN PLAN FOR
SELECT * FROM nullable_column WHERE NVL(data, 'NULL') = 'NULL';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Explanation: The NVL function converts NULLs to a specific value, allowing
the index to be used.

Demo 6: Index Not Used Due to Implicit Type

Conversion

Issue: Implicit type conversion prevents Oracle from using the index.

Solution: Ensure the data types in the query match the column's data type.

sql
Copy
-- Query with explicit type conversion
EXPLAIN PLAN FOR
SELECT * FROM type_conversion WHERE code = '123';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: By ensuring the query uses the correct data type ( VARCHAR2 in
this case), Oracle can use the index.

Demo 7: Index Not Used Due to OR Condition

Issue: Oracle might not use indexes due to an OR condition.

Solution: Rewrite the query using UNION ALL or use a composite index.

sql
Copy
-- Rewrite the query using UNION ALL
EXPLAIN PLAN FOR
SELECT * FROM or_condition WHERE col1 = 'Data500'
UNION ALL
SELECT * FROM or_condition WHERE col2 = 'Info500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Explanation: Splitting the query into two parts allows Oracle to use the
indexes on col1 and col2.

Demo 8: Index Not Used Due to CBO Decision

Issue: The Cost-Based Optimizer (CBO) decides that using the index is not
cost-effective.

Solution: Gather fresh statistics or use a hint to force index usage.

sql
Copy
-- Gather fresh statistics
EXEC DBMS_STATS.GATHER_TABLE_STATS('YOUR_SCHEMA',
'large_table');

-- Force Oracle to use the index


EXPLAIN PLAN FOR
SELECT /*+ INDEX(large_table idx_data) */ * FROM large_table
WHERE data = 'Data50000';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Fresh statistics help the CBO make better decisions. If


necessary, use a hint to force index usage.

Demo 9: Index Not Used Due to Index Invisibility

Issue: The index is invisible, so Oracle ignores it.

Solution: Make the index visible.

sql
Copy
-- Make the index visible
ALTER INDEX idx_data VISIBLE;

-- Query the table


EXPLAIN PLAN FOR
SELECT * FROM invisible_index WHERE data = 'Data500';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Making the index visible allows Oracle to consider it for query
optimization.

Demo 10: Index Not Used Due to Parallel Execution

Issue: Oracle prefers a full table scan with parallel execution.

Solution: Disable parallel execution or use a hint to force index usage.

sql
Copy
-- Disable parallel execution
ALTER TABLE parallel_table NOPARALLEL;

-- Force Oracle to use the index


EXPLAIN PLAN FOR
SELECT /*+ INDEX(parallel_table idx_data) */ * FROM parallel_table
WHERE data = 'Data500000';

-- Display the execution plan


SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explanation: Disabling parallel execution or using a hint can force Oracle to


use the index.

General Tips to Ensure Index Usage

1. Use Appropriate Indexes: Create indexes on columns used


in WHERE, JOIN, and ORDER BY clauses.

2. Avoid Implicit Type Conversion: Ensure the query's data types


match the column's data types.
3. Gather Statistics: Regularly gather statistics to help the CBO make
better decisions.

4. Use Hints Sparingly: Use hints like /*+ INDEX */ to force index usage,
but only when necessary.

5. Rewrite Queries: Simplify queries and avoid conditions that prevent


index usage (e.g., OR, functions).

6. Check Index Visibility: Ensure the index is visible to the optimizer.

By addressing these issues, you can improve the likelihood of Oracle using
indexes effectively.

You might also like