2014-10-28 75 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查詢,計劃等),您可以獲得更多幫助。