Могут ли переменные PL изменяться во время запросов SQL (почему Oracle не оптимизирует мой простой запрос)? - PullRequest
3 голосов
/ 10 августа 2011

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

Предположим, у вас есть таблица с именем my_table со столбцом с именем my_column и вы пишете хранимую процедуру так:

procedure my_proc(a_value my_table.my_column%type := null) is
begin
    for i in (
        select another_column from my_table
        where  a_value is null or my_column = a_value)
    loop
      -- do something
    end loop;
end;

Я всегда предполагал, что выражение a_value is null является постоянным для ради оператора select или любого выражения, состоящего исключительно из переменных PL и других констант для этого иметь значение. Другими словами, это может быть безопасно оценено до выполнения запрос и заменить константу. В этом коде, например, когда a_value не передано, запрос будет эквивалентен

select another_column from my_table

И наоборот, когда значение передано, запрос будет эквивалентен

select another_column from my_table
where my_column = a_value

К моему удивлению, эта простая оптимизация не производится. a_value is null Кажется, что выражение выполняется для каждой записи в таблице и, с достаточно большой стол, разница заметна даже без особых инструменты. Я использую версию 10 и буду рассматривать эту оптимизацию как 2.0 или 3.0 функция, которая была бы сделана давно.

Там должно быть какая-то причина для этого, очевидно. Может быть, мое предположение, что PL переменные являются константами для глаз SQL-запроса не соответствует действительности. Может быть, PL переменные могут изменяться во время выполнения запросов SQL. Вы знаете о каких-либо такой случай?

1 Ответ

6 голосов
/ 10 августа 2011

Когда Oracle необходимо скомпилировать и оптимизировать SQL-запрос, он должен создать план запроса, который будет работать независимо от того, какими будут значения переменных связывания, поскольку этот план может быть повторно использован с тем же запросом, но позже с другими значениями. 1001 *

В запросе select another_column from my_table where a_value is null or my_column = a_value a_value является переменной связывания. Запрос будет жестко проанализирован в плане запроса только один раз. Он не может свернуться до select another_column from my_table, поскольку следующий вызов хранимой процедуры может перейти в ненулевое значение a_value.

РЕДАКТИРОВАТЬ Добавление примера.

Ask Tom имеет сообщение , в котором рассматривается более сложная версия этой проблемы. На основании его ответа.

Пример данных:

create table my_table(my_column varchar2(10) null
    , another_column varchar2(10) null)
/
insert into my_table values('1', 'a');
insert into my_table values('2', 'b');
insert into my_table values('3', 'c');
insert into my_table values('4', 'd');
insert into my_table values('5', 'e');
insert into my_table values('6', 'f');
insert into my_table values('7', 'g');
insert into my_table values('8', 'h');
insert into my_table values('9', 'i');
insert into my_table values('10', 'j');
commit;

Процедура:

create or replace procedure my_proc(p_value in my_table.my_column%TYPE default null) is
    type l_rec_type is record(another_column my_table.another_column%TYPE);
    l_sql varchar2(32767) := 'select another_column from my_table where ';
    l_cursor sys_refcursor;
    l_record l_rec_type;
begin
    if p_value is null then 
        l_sql := l_sql || '(1=1 or :my_column is null)';
    else 
        l_sql := l_sql || '(my_column = :my_column)';
    end if;
    open l_cursor for l_sql using p_value;
    loop
        fetch l_cursor into l_record;
        exit when l_cursor%NOTFOUND;
        -- do something
        dbms_output.put_line(l_record.another_column);
    end loop;
    close l_cursor;
end my_proc;
/

Смотри, как он работает:

SQL> exec my_proc()
a
b
c
d
e
f
g
h
i
j

PL/SQL procedure successfully completed.

SQL> exec my_proc('2')
b

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