Чи можу я покластися на функції, що виконуються спочатку в 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?


Не можу не думати, що тригер для входу може бути більш підходящим (якщо рівень завжди буде однаковим, тобто)
Philᵀᴹ

@Phil це лише приклад - я використовую sys_context для параметризації подання, і параметр буде кожен раз відрізнятися. Якщо ви знаєте спосіб встановити глобальний контекст із SQL, не плутаючись подібного, мені також цікаво це почути!
Джек каже, спробуйте topanswers.xyz

1
@JackDouglas: параметризація погляду - це ідея, яка не "відчуває мене" правильно. У MSSQL те, що ви намагаєтеся зробити, можна зробити за допомогою визначеної користувачем функції, яка повертає набір результатів (а не значення), - ви можете потім SELECT stuff FROM dbo.FuncReturningTable(param)чи подібне. Oracle, ймовірно, має еквівалентну функціональність. Хоча якщо ви користуєтеся цим у великих наборах даних, я буду ретельно контролювати продуктивність: я не впевнений, наскільки яскравим повинен бути планувальник запитів, щоб зробити ефективний план із такого синтаксису.
Девід Спіллетт

@David параметризація подання зазвичай робиться за допомогою sys_context - просто зазвичай ви встановите контекст перед виконанням запиту (наприклад, з трохи PL / SQL). Oracle має функцію повернення та / або конвеєри, але вони не є "нормальним" способом досягнення цього. Щоб було зрозуміло, я думаю, що відповідь на запитання в заголовку - «ні» - я просто задумався, чи хтось знає краще.
Джек каже, спробуйте topanswers.xyz

Відповіді:


8

Ні.

Якщо ви перезапишете свій погляд з фільтруванням контексту у відповідність до пункту where (замість підключення 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 

Оскільки стаття де оцінюється до вибору стовпців, значення, передане функції, не встановлюється, поки не буде прочитаний контекст. Розташування виклику sys_context у вашому запиті (виберіть, де, групувати тощо) буде впливати саме тоді, коли встановлено це значення.


+1, це майже в "моєму випадку" закрито, дякую.
Джек каже, спробуйте topanswers.xyz

2

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

Якби планувальник запитів був досить яскравим, щоб виявити, що на подання впливають побічні ефекти функції, що це зробить, якщо ви приєднаєтесь до іншого представлення, яке викликало цю функцію потенційно з різними вхідними значеннями? Це може досить швидко стати дуже волохатим - така річ, чому загалом, в будь-якому контексті програмування, функції не повинні мати наслідків, що перевищують їх власні результати.

У цьому конкретному прикладі я б сказав, що навряд чи f (x) буде викликано першим, оскільки це є "він" частиною висловлення: результат, встановлений з подання, можливо, буде отриманий перед будь-якими функціями в межах список стовпців для повернення оцінюється. Звичайно, це буде різнитися залежно від використовуваної СУБД: Я не експерт Oracle, а ваші результати тестування показують, що функція, як видається, викликається спочатку в цих випадках. Але я б насторожено покладався на порядок виконання в будь-якому одному викладі SQL все одно - навіть якщо він завжди працює так, як ви зараз очікуєте, він може не робити цього в майбутніх редакціях (якщо це не буде офіційно зафіксовано десь, виконання завжди буде йти цей шлях навколо).


2
Гарна відповідь, але я відчуваю, що Джек шукає остаточну технічну відповідь Oracle.
Philᵀᴹ

1

Документація лише обіцяє, що "Оптимізатор спочатку максимально повно оцінює вирази та умови, що містять константи". ( 10.2 , 11.2 ). Ви не впевнені, що він спочатку оцінить якийсь конкретний вираз або що він не буде змінювати цей порядок час (новий патч-рівень у тому ж випуску?).


+1 відмінно, дякую (хоча, моєму читанню, ці документи не зовсім квадратні з відповіддю Кріса )
Джек каже, спробуйте topanswers.xyz

1
Різниця полягає в тому, чи викликається функція в пункті де, select або в якомусь іншому пункті. Функції в розділі вибору не впливатимуть на рішення оптимізатора (якщо це не підзапит), тому їх не потрібно оцінювати до отримання результатів. Функції пункту де впливатимуть на метод з'єднання, який використовується, тому їх потрібно оцінити якомога швидше.
Кріс Саксон

@Chris - це досвід говорити чи ти це діставав у документів десь?
Джек каже, спробуйте topanswers.xyz

Я не можу знайти посилання на документ. Виходячи з мого досвіду, якщо виклик у пункті де фільтрувати одну таблицю, вона буде доступна для кожного рядка (якщо вважати FTS), але тільки для рядків, що повертаються, якщо у списку вибору. Оскільки план виконання встановлюється під час розбору, це означає, що функції у виборі не можуть впливати на нього. Тестовий випадок, щоб перевірити це, можна зробити, створивши функцію, що встановлює лічильник (в пакеті або таблиці) та порівнявши вихід, залежно від того, де в запиті він розміщений.
Кріс Саксон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.