Могу ли я рассчитывать на функции, выполняемые в первую очередь в SQL

9

Пожалуйста, рассмотрите следующий скрипт:

create or replace function f(p_limit in integer) return integer as
begin
  set_global_context ('limit', p_limit);
  return p_limit;
end;
/

create view v as 
select level as val from dual connect by level<=sys_context('global_context','limit');

select f(2), v.* from v;

/*
F(2)                   VAL                    
---------------------- ---------------------- 
2                      1                      
2                      2                      
*/

select f(4), v.* from v;

/*
F(4)                   VAL                    
---------------------- ---------------------- 
4                      1                      
4                      2                      
4                      3                      
4                      4                      
*/

Могу ли я рассчитывать на f(x)выполнение до того, как контекст будет прочитан внутри представления, как это было в этом тестовом примере на 10.2?

Джек говорит, попробуйте topanswers.xyz
источник
Не могу не думать, что триггер входа может быть более подходящим (если уровень всегда будет одинаковым, то есть)
Philᵀᴹ
@Phil, это всего лишь пример - я использую sys_context для параметризации представления, и параметр будет отличаться каждый раз. Если вы знаете способ установки глобального контекста из SQL без возни с этим, мне также было бы интересно это услышать!
говорит Джек, попробуйте topanswers.xyz
1
@JackDouglas: параметризация представления - это идея, которая мне не «кажется» подходящей. В MSSQL то, что вы пытаетесь сделать, может быть сделано с помощью пользовательской функции, которая возвращает результирующий набор (а не значение), - тогда вы можете сделать это SELECT stuff FROM dbo.FuncReturningTable(param)или подобное. Oracle, вероятно, имеет эквивалентную функциональность. Хотя, используя это для больших наборов данных, я бы внимательно следил за производительностью: я не уверен, насколько ярким должен быть планировщик запросов, чтобы составить эффективный план с таким синтаксисом.
Дэвид Спиллетт
@ Дэвид параметризация представления обычно выполняется с помощью sys_context - обычно вы устанавливаете контекст до выполнения запроса (например, с небольшим количеством PL / SQL). В Oracle есть функции возврата и / или конвейеризации, но они не являются «нормальным» способом достижения этого. Чтобы быть ясным, я думаю, что ответ на вопрос в названии «нет» - я просто подумал, знает ли кто-то лучше.
Джек говорит, попробуйте topanswers.xyz

Ответы:

8

Нет.

Если вы переписываете свое представление с фильтрацией контекста по предложению where (вместо connect by), вы получите предварительно установленное значение для контекста:

create table t as 
 select rownum r from dual connect by level <= 10;

create or replace view v as 
  select r val from t where r <=sys_context('global_context','limit');

select f(2), v.* from v;

F(2) VAL
---- ---
   2   1 
   2   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 
   4   3 
   4   4 

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

Крис Саксон
источник
+1 Это довольно много "дело закрыто" в моей книге, спасибо.
говорит Джек, попробуйте topanswers.xyz
2

Вообще говоря, вы не можете с уверенностью предположить что-либо о порядке, в котором ваша СУБД будет действовать при оценке одного оператора SQL. Вот почему многие СУБД не позволяют таким функциям иметь побочные эффекты (т. Е. MSSQL не позволяет функциям устанавливать глобальное состояние / состояние соединения, которое вы там делаете, или изменять содержимое таблицы). Последовательность операторов должна выполняться так, чтобы иметь смысл от одного шага к следующему (то есть они выполняются последовательно или таким образом, что вы не можете сказать, что это не так), но внутри одного оператора планировщик запросов имеет свободное правление до тех пор, пока оно не вводит неоднозначность там, где ее еще нет (в вашем примере неоднозначность уже существует, поскольку функция имеет побочный эффект, влияющий на представление).

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

В этом конкретном примере я бы сказал, что маловероятно, что f (x) будет вызван первым, поскольку он «отображает» часть оператора: результирующий набор из представления, вероятно, будет получен до каких-либо функций внутри список возвращаемых столбцов оценивается. Конечно, это будет зависеть от используемой СУБД: я не эксперт Oracle, и результаты ваших тестов показывают, что в этих случаях эта функция вызывается первой. Но я бы все же опасался полагаться на порядок выполнения в любом отдельном операторе SQL - даже если он всегда работает так, как вы ожидаете сейчас, это может не сработать в будущих ревизиях (если только где-то не будет официально задокументировано, что выполнение всегда будет идти так наоборот).

Дэвид Спиллетт
источник
2
Хороший ответ, но я чувствую, что Джек ищет точный технический ответ Oracle.
Philᵀᴹ
1

Документация только обещает, что «оптимизатор сначала оценивает выражения и условия, содержащие константы, как можно полнее». ( 10.2 , 11.2 ). Вам не гарантируется, что он сначала оценит какое-либо конкретное выражение или что он не будет время от времени изменять этот порядок (новый уровень исправлений в том же выпуске?).

Стивен Кендалл
источник
+1 отлично, спасибо (хотя, читая эти документы, я не совсем
согласен
1
Разница заключается в том, вызывается ли функция в предложении where, select или в каком-либо другом предложении. Функции в разделе выбора не влияют на решения оптимизатора (если это не подзапрос), поэтому их не нужно оценивать до получения результатов. Однако функции в предложении where будут влиять на используемый метод соединения, поэтому его необходимо оценить как можно скорее.
Крис Саксон
@ Крис, этот опыт говорит, или ты где-то получил это из документации?
говорит Джек, попробуйте topanswers.xyz
Я не могу найти ссылку на документ. Исходя из моего опыта, если вызывать в предложении where для фильтрации одной таблицы, он будет доступен для каждой строки (при условии FTS), но только для строк, возвращаемых в списке выбора. Поскольку план выполнения устанавливается во время синтаксического анализа, это означает, что функции в select не могут повлиять на него. Тестовый пример для проверки этого можно выполнить, создав функцию, устанавливающую счетчик (в пакете или таблице), и сравнив выходные данные в зависимости от того, где в запросе они размещены.
Крис Саксон