2010-07-14 2 views
1

Я работаю на столе, который имеет 3008698 строкиесть хитрый способ оптимизировать этот запрос

exam_date является DATE поля.

Но запросы, которые я запускаю, хотят соответствовать только части месяца. Так что я делаю:

select * from my_big_table where to_number(to_char(exam_date, 'MM')) = 5; 

, который, как я считаю, длится долго из-за функции на колонке. Есть ли способ избежать этого и сделать его быстрее? кроме внесения изменений в таблицу? exam_date в таблице имеют разные значения даты. как 01-OCT-10 или 12-OCT-10 ... и так далее

+0

Планы SQL и SQL-команд harfor SQL помогут вам. Убедитесь, что статистика ваших таблиц актуальна – cagcowboy

+0

Основной вопрос, но действительно ли таблица имеет индекс на exam_date? (Тот факт, что ваша производительность отличается при выполнении проверки диапазона, предполагает, что она делает). Замечания APC о сканировании в полноэкранном режиме важны - если ваши данные равномерно распределены через 12 месяцев, и вам нужно вернуть 1/12 из 3008698 строк, то, вероятно, лучше всего сканировать полный стол, а также много данных. Один из способов ускорить полномасштабное сканирование - это посмотреть на/* + PARALLEL */hint Oracle (который делит полное сканирование на ваши процессоры), но есть затраты на повторную сборку результатов. – JulesLt

ответ

3
select * from my_big_table where MONTH(exam_date) = 5 

упс .. Oracle да? ..

select * from my_big_table where EXTRACT(MONTH from exam_date) = 5 
+0

+1 У Oracle есть несколько эффективных методов обработки дат, которые вы должны использовать в WHERE, потому что они могут использовать индекс по-странным. –

+1

@learn_plsql, насколько быстрее это? Oracle все еще должна выполнить полное сканирование таблицы. Вы пробовали индекс на основе функции? Это может или не поможет, поскольку данные имеют не более 12 различных значений. – redcayuga

5

Я не знаю, Oracle, но как насчет Производство

WHERE exam_date BETWEEN first_of_month AND last_of_month 

где две даты являются постоянными выражениями.

+0

Выполнение: 'exam_date между To_date ('11/01/2010 ',' MM/DD/YYYY ') и to_date ('11/30/2010', 'MM/DD/YYYY')' на самом деле занимает больше времени ... –

+0

Ну, это стоило выстрела :) – harpo

1

Вызов функции означает, что Oracle не сможет использовать какой-либо индекс, который может быть определен в столбце.

Либо удалите вызов функции (как в ответе Гарпо), либо используйте индекс, основанный на функции.

3

Имейте в виду, что, поскольку вы хотите получить приблизительно 1/12-й из всех данных, вполне возможно, что Oracle сможет выполнить полное сканирование таблицы в любом случае. Это может объяснить, почему производительность была хуже, когда вы следовали советам гарпо.

Почему? Предположим, что ваши данные таковы, что 20 рядов подходят для каждого блока базы данных (в среднем), так что у вас есть в общей сложности 3 000 000/20 = 150 000 блоков. Это означает, что полное сканирование таблицы потребует 150 000 блочных чтений. Теперь около 1/12 из 3 000 000 строк будет на месяц 05. 3 000 000/12 составляет 250 000. Таким образом, это 250 000 табличных таблиц, если вы используете индекс - и это игнорирует чтение индекса, которое также потребуется. Таким образом, в этом примере полное сканирование таблицы делает намного меньше работы, чем индексированный поиск.

+0

Хммм, в то время как я печатал свой ответ, вы отправили его, который также начинается «Помните о разуме», делая точно такую ​​же точку. Великие умы и все такое;) – APC

+0

Действительно - почти жуткий! –

3

Принесите в miond, что для MONTH существует только двенадцать различных значений. Поэтому, если у вас нет сильно кластерного набора записей (скажем, если вы используете partitioining), возможно, что использование индекса не обязательно является наиболее эффективным способом запроса таким образом.

я не нашел, что использование EXTRACT() приводит оптимизатор использовать обычный индекс на моей дату колонке, но YMMV:

SQL> create index big_d_idx on big_table(col3) compute statistics 
    2/

Index created. 

SQL> set autotrace traceonly explain 

SQL> select * from big_table 
    2 where extract(MONTH from col3) = 'MAY' 
    3/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3993303771 

------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   | 23403 | 1028K| 4351 (3)| 00:00:53 | 
|* 1 | TABLE ACCESS FULL| BIG_TABLE | 23403 | 1028K| 4351 (3)| 00:00:53 | 
------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter(EXTRACT(MONTH FROM INTERNAL_FUNCTION("COL3"))=TO_NUMBER('M 
       AY')) 

SQL> 

Что определенно может убедить оптимизатор использовать индекс в этих сценариях построение функционального индекса:

SQL> create index big_mon_fbidx on big_table(extract(month from col3)) 
    2/

Index created. 

SQL> select * from big_table 
    2 where extract(MONTH from col3) = 'MAY' 
    3/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 225326446 

------------------------------------------------------------------------------------------- 
| Id | Operation     | Name   | Rows | Bytes | Cost (%CPU)|Time | 
------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |    | 23403 | 1028K| 475 (0)|00:00:06| 
| 1 | TABLE ACCESS BY INDEX ROWID| BIG_TABLE  | 23403 | 1028K| 475 (0)|00:00:06| 
|* 2 | INDEX RANGE SCAN   | BIG_MON_FBIDX | 9361 |  | 382 (0)|00:00:05| 
------------------------------------------------------------------------------------------- 


Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - access(EXTRACT(MONTH FROM INTERNAL_FUNCTION("COL3"))=TO_NUMBER('MAY')) 

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