Reputation: 29
I am attempting to create a Function Based Index on a predicate that has a high cost (Oracle).
I want to create an index on the TIME_ID column in the A4ORDERS table that brings back values for month of December:
SELECT * FROM A4ORDERS WHERE TRIM(TO_CHAR(time_id, 'Month')) in ( 'December' );
Creating the FBI:
CREATE INDEX TIME_FIDX ON A4ORDERS(TRIM(TO_CHAR(time_id, 'Month')) in ( 'December' ));
I get a "Missing Right parenthesis" error and I can't figure out why? Any guidance you can provide would be appreciated.
Solution from Alex Poole's response below that worked:
CREATE INDEX TIME_FIDX ON A4ORDERS (TRIM(TO_CHAR(time_id, 'Month')));
Upvotes: 0
Views: 117
Reputation: 191275
Your create index
statement should not have the in ( 'December' )
part, that only belongs in the query. If you create the index as:
CREATE INDEX TIME_FIDX ON A4ORDERS (TRIM(TO_CHAR(time_id, 'Month')));
... then that index can be used by your query:
EXPLAIN PLAN FOR
SELECT * FROM A4ORDERS WHERE TRIM(TO_CHAR(time_id, 'Month')) in ( 'December' );
SELECT plan_table_output FROM TABLE (dbms_xplan.display());
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| A4ORDERS | 1 | 29 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | TIME_FIDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(TRIM(TO_CHAR(INTERNAL_FUNCTION("TIME_ID"),'Month'))='December')
So you can see from the plan that TIME_FIDX
is being used. Whether it will give you a significant performance gain remains to be seen of course, and the optimiser could decide it isn't selective enough anyway.
'Month' is NLS-sensitive though; it would be safer to either use the month number, or specify the NLS_DATE_LANGUAGE in the TO_CHAR
call, but it has to be done consistently - which will be a little easier with numbers. You could also make it an indexed virtual column.
Upvotes: 2
Reputation: 5565
You can use:
CREATE INDEX TIME_FIDX ON A4ORDERS(TRIM(TO_CHAR(time_id, 'Month')));
But also you can make it bit more simple:
CREATE INDEX TIME_FIDX ON A4ORDERS(TO_CHAR(time_id, 'mm'));
and write SQL:
SELECT * FROM A4ORDERS WHERE TO_CHAR(time_id, 'mm') in ( '12');
But if you provide more information about your problem (workaround, SQL query, plans etc.) you can receive more help.
Upvotes: 2