Czy mogę polegać na funkcjach wykonywanych jako pierwsze w SQL

9

Proszę wziąć pod uwagę następujący skrypt:

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                      
*/

Czy mogę polegać na f(x)tym, że kontekst zostanie odczytany w widoku, tak jak w tym przypadku testowym uruchomionym na 10.2?

Jack mówi, że spróbuj topanswers.xyz
źródło
Nic na to nie poradzę, ale wydaje mi się, że wyzwalacz logowania może być bardziej odpowiedni (to znaczy, jeśli poziom zawsze będzie taki sam)
Philᵀᴹ
@Phil to tylko przykład - używam sys_context do parametryzacji widoku, a parametry będą za każdym razem inne. Jeśli znasz sposób na ustawienie globalnego kontekstu z SQL bez bałagania się w ten sposób, również chciałbym to usłyszeć!
Jack mówi: spróbuj topanswers.xyz
1
@JackDouglas: parametryzowanie widoku to pomysł, który nie jest dla mnie odpowiedni. W MSSQL to, co próbujesz zrobić, można wykonać za pomocą funkcji zdefiniowanej przez użytkownika, która zwraca zestaw wyników (zamiast wartości), - możesz to zrobić SELECT stuff FROM dbo.FuncReturningTable(param)lub podobnie. Oracle prawdopodobnie ma równoważną funkcjonalność. Chociaż używając tego do dużych zestawów danych, uważnie monitoruję wydajność: nie jestem pewien, jak jasne musiałoby być narzędzie do planowania zapytań, aby stworzyć wydajny plan z takiej składni.
David Spillett
@David parametryzacja widoku jest zwykle wykonywana za pomocą sys_context - normalnie ustawiasz kontekst przed wykonaniem zapytania (np. Z odrobiną PL / SQL). Oracle ma funkcje zwracające zestaw i / lub potokowe, ale nie są to „normalne” sposoby osiągnięcia tego. Dla jasności uważam, że odpowiedź na pytanie w tytule brzmi „nie” - po prostu zastanawiałam się, czy ktoś wiedział lepiej.
Jack mówi, że spróbuj topanswers.xyz

Odpowiedzi:

8

Nie.

Jeśli ponownie napiszesz widok z filtrowaniem kontekstu względem klauzuli where (zamiast connect by), otrzymasz poprzednio ustawioną wartość dla kontekstu:

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 

Ponieważ klauzula where jest oceniana przed zaznaczeniem kolumn, wartość przekazywana do funkcji nie jest ustawiana, dopóki nie zostanie odczytany kontekst. Lokalizacja wywołania sys_context w zapytaniu (wybierz, gdzie, grupuj według itd.) Wpłynie dokładnie na ustawienie tej wartości.

Chris Saxon
źródło
+1, co w mojej książce jest prawie „zamknięte”, dzięki.
Jack mówi, że spróbuj topanswers.xyz
2

Ogólnie rzecz biorąc, nie można bezpiecznie zakładać niczego o kolejności, w jakiej DBMS zrobi rzeczy podczas oceny pojedynczej instrukcji SQL. To dlatego wiele DBMS nie pozwala funkcjom używanym w ten sposób wywoływać skutki uboczne (tj. MSSQL nie pozwala funkcjom ustawiać stanu globalnego / połączenia, który tam robisz, ani zmieniać zawartości tabeli). Szereg instrukcji musi być wykonywany w sposób, który ma sens z jednego kroku do następnego (tj. Są uruchamiane szeregowo lub w sposób, którego nie można powiedzieć, że nie były), ale w ramach pojedynczej instrukcji planista zapytań ma wolne panowanie, o ile nie wprowadza dwuznaczności tam, gdzie jeszcze nie istnieje (w twoim przykładzie niejasność już istnieje, ponieważ funkcja ma efekt uboczny wpływa na widok).

Gdyby planista zapytań był wystarczająco jasny, aby wykryć, że na widok wpływają efekty uboczne funkcji, co zrobiłby, gdybyś dołączył do innego widoku, który wywołał tę funkcję potencjalnie z różnymi wartościami wejściowymi? Może dość szybko stać się bardzo włochaty - z tego powodu ogólnie rzecz biorąc, w jakimkolwiek kontekście programowania, funkcje nie powinny mieć efektów wykraczających poza ich własne wyniki.

W tym konkretnym przykładzie powiedziałbym, że jest mało prawdopodobne, aby f (x) został wywołany jako pierwszy, ponieważ jest to część „wyświetlająca” instrukcję: zestaw wyników z widoku prawdopodobnie zostanie pobrany przed jakąkolwiek funkcją w lista kolumn do zwrócenia jest oceniana. Oczywiście będzie się to różnić w zależności od zastosowanego DBMS: nie jestem ekspertem Oracle, a wyniki testu pokazują, że funkcja wydaje się być wywoływana jako pierwsza w tych przypadkach. Byłbym jednak ostrożny, polegając na tym samym poleceniu wykonania w ramach pojedynczej instrukcji SQL - nawet jeśli zawsze działa tak, jak się teraz spodziewasz, może nie zrobić tego w przyszłych wersjach (chyba że gdzieś jest oficjalnie udokumentowane, że wykonanie zawsze pójdzie w ten sposób).

David Spillett
źródło
2
Dobra odpowiedź, ale uważam, że Jack szuka ostatecznej technicznej odpowiedzi Oracle.
Philᵀᴹ
1

Dokumentacja obiecuje tylko, że „Optymalizator najpierw ocenia wyrażenia i warunki zawierające stałe tak dokładnie, jak to możliwe”. ( 10,2 , 11,2 ). Nie masz gwarancji, że najpierw oceni jakieś wyrażenie lub że od czasu do czasu nie zmieni tej kolejności (nowy poziom łatki w tej samej wersji?).

Stephen Kendall
źródło
+1 doskonale, dziękuję (chociaż dzięki mojemu czytaniu te dokumenty nie do końca odpowiadają odpowiedzi Chrisa )
Jack mówi, że spróbuj topanswers.xyz
1
Różnica polega na tym, czy funkcja jest wywoływana w klauzuli where, select czy w innej klauzuli. Funkcje w sekcji wyboru nie wpłyną na decyzje optymalizatora (chyba, że ​​jest to podzapytanie), więc nie trzeba ich oceniać przed pobraniem wyników. Funkcje w klauzuli where będą miały wpływ na zastosowaną metodę łączenia, dlatego należy je ocenić tak szybko, jak to możliwe.
Chris Saxon
@Chris to doświadczenie mówienia, czy otrzymałeś je gdzieś z dokumentów?
Jack mówi, że spróbuj topanswers.xyz
Nie mogę znaleźć odniesienia do dokumentu. Z mojego doświadczenia wynika, że ​​jeśli zostanie wywołana w klauzuli where w celu przefiltrowania pojedynczej tabeli, będzie ona dostępna dla każdego wiersza (zakładając FTS), ale tylko dla wierszy zwróconych, jeśli na liście wyboru. Ponieważ plan wykonywania jest ustawiany podczas analizowania, oznacza to, że funkcje w select nie mogą go zmienić. Przypadek testowy, aby to sprawdzić, można wykonać, tworząc funkcję ustawiającą licznik (w pakiecie lub tabeli) i porównując dane wyjściowe na podstawie tego, w którym miejscu zapytania jest umieszczone.
Chris Saxon