2014-10-28 3 views
0

Я пытаюсь создать индекс на основе функции для предиката с высокой стоимостью (Oracle).Отсутствует ошибка в скобках при создании индекса на основе функции

Я хочу создать индекс на столбце TIME_ID в таблице A4ORDERS, который возвращает значения месяца декабря:

SELECT * FROM A4ORDERS WHERE TRIM(TO_CHAR(time_id, 'Month')) in ('December'); 

Создание ФБР:

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

Индекс не «возвращает значения». Хотите индексировать только значения в декабре? –

+0

Да, пожалуйста. Как это сделать? – ShoSom

+0

Я думаю, вы должны объяснить, что вы пытаетесь выполнить. Какой запрос вы пытаетесь оптимизировать, например? –

ответ

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; было бы безопаснее использовать номер месяца или указать NLS_DATE_LANGUAGE в вызове TO_CHAR, но это нужно сделать последовательно - что будет немного проще с цифрами. Вы также можете сделать его индексированным виртуальным столбцом.

+0

Wow. Это действительно вернуло именно то, что я хотел. Спасибо. – ShoSom

+0

@ShoSom - вам нужен 'TRIM', потому что по умолчанию все имена месяцев заполняются пробелами до длины самого длинного имени, которое является сентябрьским (с английским языком данных!). Без обрезки ваше индексированное значение равно '' декабрь '' с конечным пространством. Вы также можете использовать [модификатор 'FM'] (http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements004.htm#SQLRF00216), т. Е.'fmMonth', чтобы в первую очередь не было добавлено значение, а затем вам не нужно обрезать. Но запрос должен делать то же самое, что и индекс. Другая причина номера проще ... –

+0

Это имеет большой смысл, спасибо за подробную обратную связь - это очень ценится. – ShoSom

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-запрос, планы и т. Д.), Вы можете получить дополнительную помощь.

Смежные вопросы