Производительность Oracle с использованием функций в предложении where - PullRequest
4 голосов
/ 13 июля 2009

В хранимой процедуре (у которой есть параметр даты с именем 'paramDate'), у меня есть такой запрос

select id, name
from customer
where period_aded = to_char(paramDate,'mm/yyyy')

Будет ли Oracle преобразовывать paramDate в строку для каждой строки?

Я был уверен, что Oracle не будет, но мне сказали, что Oracle будет. На самом деле я думал, что если параметром функции является ограничение (не полученное ни поле, ни вычисленное значение внутри запроса), результат должен быть всегда одинаковым, и поэтому Oracle должна выполнить это преобразование только один раз. Затем я понял, что иногда выполняю предложения DML в нескольких функциях, и, возможно, это может привести к изменению результирующего значения, даже если оно не изменяется для каждой строки.

Это должно означать, что я должен преобразовать такие значения, прежде чем добавить их в запрос.

В любом случае, возможно, хорошо известные функции (встроенные) оцениваются один раз, или даже мои функции также будут.

В любом случае, снова ...

Оракул выполнит этот to_char один раз или Oracle сделает это для каждой строки?

Спасибо за ваши ответы

Ответы [ 3 ]

8 голосов
/ 13 июля 2009

Я не думаю, что это обычно так, поскольку это помешало бы использованию индекса.

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

Вот случай, когда используется индекс (и функция оценивается не для каждой строки):

SQL> select id from tbl_table where id > to_char(sysdate, 'YYYY');

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |    35 |   140 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| SYS_C004274 |    35 |   140 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

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

1 - access("ID">TO_NUMBER(TO_CHAR(SYSDATE@!,'YYYY')))

Для пользовательских функций ознакомьтесь с этой статьей . Упоминается два способа обеспечения что ваша функция вызывается только один раз:

  1. Начиная с Oracle 10.2, вы можете определить функцию как DETERMINISTIC.

  2. В старых версиях вы можете перефразировать его, чтобы использовать «скалярное подзапросное кэширование»:

    ВЫБРАТЬ СЧЕТ (*) ОТ СОТРУДНИКОВ WHERE SALARY = (ВЫБЕРИТЕ getValue (1) FROM DUAL);

1 голос
/ 13 июля 2009

Рассматривая рецензии на ключевое слово DETERMINISTIC ( здесь одно , здесь другое ), оно было введено, чтобы позволить разработчику сообщить Oracle, что функция вернет то же значение для тех же входных параметров. Поэтому, если вы хотите, чтобы ваши функции вызывались только один раз, , и вы можете гарантировать, что они всегда будут возвращать одно и то же значение для одних и тех же входных параметров , вы можете использовать ключевое слово DETERMINISTIC.

Что касается встроенных функций, таких как to_char, я обращаюсь к тем, кто лучше разбирается во внутренностях Oracle, чтобы дать вам направление.

1 голос
/ 13 июля 2009

Забота о to_char не звонит мне в колокольчик. Тем не менее, в вашем PL / SQL, вы могли бы иметь

create or replace procedure ........
  some_variable varchar2(128);
begin

  some_variable := to_char(paramDate,'mm/yyyy');

  -- and your query could read

  select id, name from customer where period_aded = some_variable;
.
.
.
end;
/

Кт

...