Suppose you want to find out which type of index is best for performance with your workload. Why not set up a competition and let the optimizer decide? The playground:
ADAM@pdb1 > select max(amount_sold) from sales where channel_id=9; MAX(AMOUNT_SOLD) ---------------- 5000 ADAM@pdb1 > @lastplan PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------- SQL_ID 3hrvrf1r6kn8s, child number 0 ------------------------------------- select max(amount_sold) from sales where channel_id=9 Plan hash value: 3593230073 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 4 (100)| | | 1 | SORT AGGREGATE | | 1 | 6 | | | | 2 | TABLE ACCESS BY INDEX ROWID BATCHED| SALES | 1 | 6 | 4 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | BSTAR | 1 | | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("CHANNEL_ID"=9) 20 rows selected.
There is a standard B*tree index on the column CHANNEL_ID that speeds up the SELECT above. I think a bitmap index would be better:
ADAM@pdb1 > create bitmap index bmap on sales(channel_id) invisible nologging; Index created. ADAM@pdb1 > alter index bstar invisible; Index altered. ADAM@pdb1 > alter index bmap visible; Index altered. ADAM@pdb1 > select max(amount_sold) from sales where channel_id=9; MAX(AMOUNT_SOLD) ---------------- 5000 ADAM@pdb1 > @lastplan PLAN_TABLE_OUTPUT --------------------------------------------------------------------------------------------- select max(amount_sold) from sales where channel_id=9 Plan hash value: 2178022915 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 6 | | | | 2 | TABLE ACCESS BY INDEX ROWID BATCHED| SALES | 1 | 6 | 3 (0)| 00:00:01 | | 3 | BITMAP CONVERSION TO ROWIDS | | | | | | |* 4 | BITMAP INDEX SINGLE VALUE | BMAP | | | | | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("CHANNEL_ID"=9) 21 rows selected.
With this 12c New Feature (two indexes on the same column), I got a smooth transition to the new index type. But this left no choice to the optimizer. What about this?
ADAM@pdb1 > alter index bmap invisible; Index altered. ADAM@pdb1 > alter session set optimizer_use_invisible_indexes=true;
Now both indexes are invisible and the optimizer may choose any of them. Turns out that it likes the bitmap index better here. Instead of watching the execution plans, V$SEGMENT_STATISTICS can also be used to find out:
ADAM@pdb1 > select object_name,statistic_name,value from v$segment_statistics where object_name in ('BSTAR','BMAP') and statistic_name in ('physical reads','logical reads'); OBJECT STATISTIC_NAME VALUE ------ ------------------------------ ---------- BSTAR logical reads 22800 BSTAR physical reads 6212 BMAP logical reads 1696 BMAP physical reads 0
The numbers of BSTAR remain static while BMAP numbers increase. You may also monitor that with DBA_HIST_SEG_STAT across AWR snapshots. Now isn’t that cool? 🙂
Couple of things to be aware of here:
Watch out for more than just physical/logical reads – bitmap indexes may cause a locking problem in an OLTP environment.
Don’t keep the two indexes invisible forever – after you saw which one performs better, drop the other one. Invisible indexes need to be maintained upon DML and therefore slow it down.
#1 von ferny am August 9, 2016 - 17:43
what commands are in „lastplan.sql“ script?
#2 von Uwe Hesse am August 11, 2016 - 09:24
lastplan.sql does this: select plan_table_output from table(dbms_xplan.display_cursor); That shows the execution plan of the last SQL in the session, taken from the library cache.
#3 von Betty Zheng am September 26, 2016 - 19:22
wow very nice try, thanks for posting!
#4 von dba am September 27, 2016 - 16:15
when creating the bitmap index on the same column, I got ORA-01408: such column list already indexed. Is there any setting I have to turn on? 12.1.0.2 is my version.
#5 von Uwe Hesse am September 27, 2016 - 16:47
@Betty, thank you for leaving a nice feedback, I appreciate it 🙂
#6 von Uwe Hesse am September 27, 2016 - 16:48
@dba, maybe you forgot to create the index invisible? Also, the index type of the new index must be different from the existing index.
#7 von Sam am September 27, 2016 - 19:33
Thank you, its really helpfull.