2014-10-28 46 views
0

我试图在成本高的谓词(Oracle)上创建基于函数的索引。创建基于函数的索引时缺少括号错误

我想创建的A4ORDERS表带回值,月月的TIME_ID列的索引:

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')); 

我得到一个“失踪右括号“错误,我不明白为什么?任何指导,你可以提供将不胜感激。从下面亚历克斯·普尔的响应

解决方案工作:

CREATE INDEX TIME_FIDX ON A4ORDERS (TRIM(TO_CHAR(time_id, 'Month'))); 
+1

索引不会“带回值”。你只想在12月的价值指数? – 2014-10-28 16:24:34

+0

是的,请。我如何实现这一目标? – ShoSom 2014-10-28 16:26:17

+0

我想你应该解释你正在努力完成什么。例如,您试图优化哪个查询? – 2014-10-28 16:27:17

回答

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会更安全,但必须始终如一地完成 - 数字会更容易一些。您也可以将其设为索引虚拟列。

+0

哇。这实际上带回了我想要的。谢谢。 – ShoSom 2014-10-28 17:06:34

+0

@ShoSom - 你需要'TRIM',因为默认情况下所有的月份名称都用空格填充,最长的名字是9月份(使用英语数据语言!)。如果没有修剪,您的索引值是带有尾部空格的“December”。您也可以使用['FM'修饰符](http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements004.htm#SQLRF00216),即'fmMonth',首先没有填充值,然后你不需要修剪。但查询必须与索引完全相同。数字更简单的另一个原因... – 2014-10-28 17:13:21

+0

这使得很多的意义,谢谢你的详细反馈 - 这是非常感谢。 – ShoSom 2014-10-28 18:03:49

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查询,计划等),您可以获得更多帮助。