Is there any trick/workaround to index just partial data. For example only that data will go in index for which B IS NOT NULL.
You could do this with a function-based index. In their example for conditional uniqueness it says:
Oracle Database does not store in the index any rows where all the keys are NULL.
You aren't doing exactly the same thing but can use the same mechanism:
create index J on TEST (case when B is not null then A end, B);
Let's say your table is as simple as you showed, and has 100000 rows for the same A value, 99998 of which have B set to null and the other two have non-null values.
create table test (a number not null, b number);
insert into test values (1, 1);
insert into test values (1, 2);
insert into test select 1, null from dual connect by level < 99999;
and you create your original index and the function-based index:
create index I on TEST (A,B);
create index J on TEST (case when B is not null then A end, B);
Then you if you gather stats you can see the number of rows in each index:
select index_name, num_rows from user_indexes where index_name in ('I','J');
INDEX_NAME NUM_ROWS
------------------------------ ----------
I 1000000
J 2
Your query uses the smaller index, according to the execution plan:
var v1 number;
exec :v1 := 1;
set autotrace on
select * from test where a = :v1 and b is not null;
A B
---------- ----------
1 1
1 2
Explain Plan
-----------------------------------------------------------
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------
Plan hash value: 3591688522
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 10 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 10 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | J | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
1 - filter("A"=:V1)
2 - filter("B" IS NOT NULL)
Statistics
-----------------------------------------------------------
4 Requests to/from client
4 consistent gets
...
If I drop the J
index and repeat the query it does a full table scan and 1610 consistent gets; you might see an I
index range scan or fast full scan depending on selectivity - as I only have one A value this doesn't quite match your scenario.