Есть ли хитрый способ оптимизировать этот запрос - PullRequest
1 голос
/ 14 июля 2010

Я работаю над таблицей, в которой 3008698 строк

exam_date - это поле DATE.

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

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

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

Ответы [ 5 ]

5 голосов
/ 14 июля 2010

Я не знаю Oracle, но что делать

WHERE exam_date BETWEEN first_of_month AND last_of_month

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

3 голосов
/ 14 июля 2010

Имейте в виду, что есть только двенадцать различных значений для МЕСЯЦА. Поэтому, если у вас нет строго кластеризованного набора записей (скажем, если вы используете 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>
3 голосов
/ 14 июля 2010

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

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

3 голосов
/ 14 июля 2010
select * from my_big_table where MONTH(exam_date) = 5

упс .. Оракул, да? ..

select * from my_big_table where EXTRACT(MONTH from exam_date) = 5
1 голос
/ 14 июля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...