Function-based indexes using NVL can solve the NULL value indexing limitation by converting NULL values to a specified non-NULL value, ensuring all rows are included in the index.
DROP INDEX idx_table_nvl_refid;
CREATE INDEX idx_table_nvl_refid ON table_nvl (NVL(refid,0));
ANALYZE INDEX idx_table_nvl_refid COMPUTE STATISTICS;
ANALYZE INDEX idx_table_nvl_refid VALIDATE STRUCTURE;
SELECT name, lf_rows FROM index_stats;
Query result:
| NAME | LF_ROWS |
+---------------------+---------+
| IDX_TABLE_NVL_REFID | 50000 |
The function-based index now contains all 50,000 rows.
NULL values in REFID are converted to 0 and stored in the index, making them searchable.
Note:
The same NVL function used in the index definition must be used in query predicates for the optimizer to recognize and utilize the index.
Standard column references will not match the function-based index.
These queries will result in full table scans because they do not match the index function:
SELECT * FROM table_nvl WHERE refid = 10;
SELECT * FROM table_nvl WHERE refid IS NULL;
SELECT * FROM table_nvl WHERE refid IS NOT NULL;
SELECT * FROM table_nvl WHERE refid > 0; -- IS NOT NULL
Execution plan:
| OBJECT_NAME | OPTIONS |
+-------------+---------+
| TABLE_NVL | FULL |
Correct usage with NVL function to utilize the function-based index:
SELECT * FROM table_nvl WHERE nvl(refid,0) = 10;
SELECT /*+ index(table_nvl idx_table_nvl_refid)*/ * FROM table_nvl WHERE nvl(refid,0) = 10;
SELECT * FROM table_nvl WHERE nvl(refid,0) = 0; -- IS NULL
SELECT /*+ index(table_nvl idx_table_nvl_refid)*/ * FROM table_nvl WHERE nvl(refid,0) = 0; -- IS NULL
SELECT * FROM table_nvl WHERE nvl(refid,0) > 0; -- IS NOT NULL
SELECT /*+ index(table_nvl idx_table_nvl_refid)*/ * FROM table_nvl WHERE nvl(refid,0) > 0; -- IS NOT NULL
Execution plan:
| OBJECT_NAME | OPTIONS |
+---------------------+----------------+
| TABLE_NVL | BY INDEX ROWID |
| IDX_TABLE_NVL_REFID | RANGE SCAN |
The function-based index enables efficient access for all scenarios: searching for specific values, NULL values (converted to 0), and NOT NULL values (greater than 0).
This approach provides comprehensive index coverage while maintaining query performance for all possible search patterns on the column.