【问题标题】:Missing parenthesis error when creating Function Based Index创建基于函数的索引时缺少括号错误
【发布时间】:2014-10-28 16:21:59
【问题描述】:

我正在尝试基于具有高成本 (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' ));

我收到“缺少右括号”错误,但我不知道为什么?您可以提供的任何指导将不胜感激。

来自 Alex Poole 的以下回复的解决方案:

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

【问题讨论】:

  • 索引不会“带回值”。您是否只想对 12 月的值进行索引?
  • 是的,请。我该如何做到这一点?
  • 我认为您应该解释您要完成的工作。例如,您要优化什么查询?
  • 您的评论让我进一步了解了这一点。我正在做的是试图让索引返回一个值。我做了一些改动,现在它可以工作了。
  • @ShoSom - 索引仍然没有返回值;您正在尝试索引从列值生成的值。我有点理解你的意思,但是当你试图解释一个问题时,术语很重要 *8-)

标签: sql oracle function indexing


【解决方案1】:

您的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 正在被使用。当然,它是否会给您带来显着的性能提升还有待观察,优化器可能会认为它的选择性不够。

'Month' 是 NLS 敏感的;使用月份编号或在 TO_CHAR 调用中指定 NLS_DATE_LANGUAGE 会更安全,但必须始终如一地完成 - 使用数字会更容易一些。您也可以将其设为索引虚拟列。

【讨论】:

  • 哇。这实际上带回了我想要的东西。谢谢。
  • @ShoSom - 您需要TRIM,因为默认情况下,所有月份名称都用空格填充到最长名称的长度,即九月(使用英语数据语言!)。如果没有修剪,您的索引值为 'December ' 并带有尾随空格。您也可以使用the FM modifier,即fmMonth,首先不填充值,然后您不需要修剪。但是查询必须与索引完全相同。另一个原因数字更简单......
  • 这很有意义,感谢您提供详细的反馈 - 非常感谢。
【解决方案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 查询、计划等),您可以获得更多帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-23
    • 2012-09-28
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 2015-03-31
    • 2016-07-15
    • 2015-04-07
    相关资源
    最近更新 更多