我正在尝试在具有高成本(Oracle)的谓词上创建基于函数的索引。
我想在A4ORDERS表中的TIME_ID列上创建一个索引,该列返回12月份的值:
SELECT * FROM A4ORDERS WHERE TRIM(TO_CHAR(time_id, 'Month')) in ( 'December' );
创建FBI:
CREATE INDEX TIME_FIDX ON A4ORDERS(TRIM(TO_CHAR(time_id, 'Month')) in ( 'December' ));
我得到一个" Missing Right括号"错误,我无法弄清楚为什么?您可以提供任何指导,我们将不胜感激。
Alex Poole的解决方案及其下面的回复有效:
CREATE INDEX TIME_FIDX ON A4ORDERS (TRIM(TO_CHAR(time_id, 'Month')));
答案 0 :(得分:2)
您可以使用:
CREATE INDEX TIME_FIDX ON A4ORDERS(TRIM(TO_CHAR(time_id, 'Month')));
但你也可以让它变得更简单:
CREATE INDEX TIME_FIDX ON A4ORDERS(TO_CHAR(time_id, 'mm'));
并编写SQL:
SELECT * FROM A4ORDERS WHERE TO_CHAR(time_id, 'mm') in ( '12');
但是,如果您提供有关您的问题的更多信息(变通方法,SQL查询,计划等),您可以获得更多帮助。
答案 1 :(得分:2)
您的create index
语句不应包含in ( 'December' )
部分,该部分仅属于查询。如果您将索引创建为:
CREATE INDEX TIME_FIDX ON A4ORDERS (TRIM(TO_CHAR(time_id, 'Month')));
...然后您的查询可以使用该索引:
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')
因此,您可以从计划中看到正在使用TIME_FIDX
。当然,它是否会给你带来显着的性能提升还有待观察,优化者可能会认为它不具备选择性。
'月'但是对NLS敏感;使用月份号码或在TO_CHAR
调用中指定NLS_DATE_LANGUAGE会更安全,但必须始终如一地进行 - 这对数字来说会更容易一些。您也可以将其设为索引虚拟列。