Dapatkah saya mengandalkan fungsi yang dijalankan pertama kali dalam SQL

9

Silakan pertimbangkan skrip berikut:

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

Dapatkah saya mengandalkan f(x)dieksekusi sebelum konteksnya dibaca di dalam tampilan, seperti yang telah dalam pengujian ini dijalankan pada 10.2?

Jack mengatakan coba topanswers.xyz
sumber
Tidak bisa tidak berpikir pemicu login mungkin lebih tepat (jika levelnya selalu sama, yaitu)
Phil
@Phil Ini hanyalah sebuah contoh - Saya menggunakan sys_context untuk parametrise view dan param akan berbeda setiap kali. Jika Anda tahu cara untuk mengatur konteks global dari SQL tanpa main-main seperti ini, saya juga akan tertarik mendengarnya!
Jack bilang coba topanswers.xyz
1
@JackDouglas: parameteraising pandangan adalah ide yang tidak "terasa" benar bagi saya. Di bawah MSSQL apa yang Anda coba lakukan bisa dilakukan menggunakan fungsi yang ditentukan pengguna yang mengembalikan resultset (bukan nilai), - Anda bisa SELECT stuff FROM dbo.FuncReturningTable(param)atau serupa. Oracle mungkin memiliki fungsi yang setara. Meskipun jika menggunakan ini pada set data besar saya akan berhati-hati untuk memantau kinerja: Saya tidak yakin seberapa cerah perencana kueri perlu membuat rencana yang efisien dari sintaksis seperti itu.
David Spillett
@ David parameteraising pandangan biasanya dilakukan dengan sys_context - biasanya Anda akan mengatur konteks sebelum mengeksekusi query (misalnya dengan sedikit PL / SQL). Oracle memiliki fungsi set-return dan / atau pipelined tetapi mereka bukan cara 'normal' untuk mencapai ini. Untuk lebih jelasnya, saya pikir jawaban untuk pertanyaan dalam judul adalah "tidak" - Saya hanya ingin tahu apakah seseorang tahu lebih baik.
Jack bilang coba topanswers.xyz

Jawaban:

8

Tidak.

Jika Anda menulis ulang tampilan Anda dengan pemfilteran konteks terhadap klausa di mana (alih-alih terhubung dengan), Anda akan mendapatkan nilai yang ditetapkan sebelumnya untuk konteks:

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 

Ketika klausa tempat dievaluasi sebelum kolom dipilih, nilai yang diteruskan ke fungsi tidak ditetapkan sampai setelah konteks dibaca. Lokasi panggilan sys_context dalam kueri Anda (pilih, di mana, kelompokkan, dll.) Akan memengaruhi tepat saat nilai ini ditetapkan.

Chris Saxon
sumber
+1 itu cukup banyak "tutup kasus" di buku saya, terima kasih.
Jack bilang coba topanswers.xyz
2

Secara umum Anda tidak dapat dengan aman berasumsi tentang urutan di mana DBMS Anda akan melakukan hal-hal ketika mengevaluasi pernyataan SQL tunggal. Inilah sebabnya mengapa banyak DBMS tidak akan mengizinkan fungsi yang digunakan seperti itu memiliki efek samping (mis. MSSQL tidak akan mengizinkan fungsi untuk mengatur global / keadaan koneksi, yang Anda lakukan di sana, atau mengubah konten tabel). Serangkaian pernyataan harus dieksekusi dengan cara yang masuk akal dari satu langkah ke langkah berikutnya (yaitu dijalankan secara seri, atau sedemikian rupa sehingga Anda tidak tahu itu tidak), tetapi dalam satu pernyataan, perencana kueri memiliki pemerintahan bebas selama itu tidak memperkenalkan ambiguitas di mana ia belum ada (dalam contoh Anda ambiguitas sudah ada karena fungsi memiliki efek samping yang mempengaruhi tampilan).

Jika perencana kueri cukup cerdas untuk mendeteksi bahwa tampilan dipengaruhi oleh efek samping fungsi, apa yang akan dilakukannya jika Anda bergabung dalam tampilan lain yang menyebut fungsi tersebut berpotensi dengan nilai input yang berbeda? Ini bisa sangat cepat menjadi sangat berbulu - hal semacam ini adalah mengapa pada umumnya, dalam konteks pemrograman apa pun, fungsi seharusnya tidak memiliki efek di luar output mereka sendiri.

Dalam contoh khusus ini saya akan mengatakan bahwa tidak mungkin bahwa f (x) akan dipanggil pertama, karena itu adalah bagian "tampilan" dari pernyataan: hasil yang ditetapkan dari tampilan cenderung diambil sebelum fungsi apa pun dalam daftar kolom untuk kembali dievaluasi. Tentu saja ini akan bervariasi tergantung pada DBMS yang digunakan: Saya bukan ahli Oracle dan hasil tes Anda menunjukkan bahwa fungsi tersebut tampaknya dipanggil pertama kali dalam hal ini. Tapi saya akan berhati-hati mengandalkan perintah eksekusi dalam pernyataan SQL tunggal semua sama - bahkan jika itu selalu bekerja seperti yang Anda harapkan saat ini mungkin tidak melakukannya dalam revisi di masa depan (kecuali jika secara resmi didokumentasikan di suatu tempat bahwa eksekusi akan selalu berjalan begini).

David Spillett
sumber
2
Jawaban yang bagus, tetapi saya merasa bahwa Jack sedang mencari jawaban teknis Oracle yang pasti.
Philᵀᴹ
1

Dokumentasi hanya menjanjikan bahwa "Pengoptimal pertama-tama mengevaluasi ekspresi dan kondisi yang mengandung konstanta semaksimal mungkin." ( 10.2 , 11.2 ). Anda tidak dijamin bahwa itu akan mengevaluasi ekspresi tertentu terlebih dahulu, atau bahwa itu tidak akan mengubah urutan itu dari waktu ke waktu (patchlevel baru dalam rilis yang sama?).

Stephen Kendall
sumber
+1 sangat bagus, terima kasih (walaupun saya membaca dokumen-dokumen itu tidak sesuai dengan jawaban Chris )
Jack mengatakan coba topanswers.xyz
1
Perbedaannya adalah apakah fungsi dipanggil di mana, pilih atau klausa lain. Fungsi di bagian pilih tidak akan memengaruhi keputusan pengoptimal (kecuali itu adalah subquery), jadi ini tidak perlu dievaluasi sampai mengambil hasilnya. Fungsi di mana klausa akan mempengaruhi metode gabungan yang digunakan, jadi perlu dievaluasi sejauh mungkin sesegera mungkin.
Chris Saxon
@ Chris adalah pengalaman itu berbicara atau Anda mendapatkan itu dari dokumen di suatu tempat?
Jack mengatakan mencoba topanswers.xyz
Saya tidak dapat menemukan referensi dokumen. Berdasarkan pengalaman saya, jika dipanggil di mana klausa untuk memfilter satu tabel itu akan diakses untuk setiap baris (dengan asumsi FTS), tetapi hanya untuk baris yang dikembalikan jika dalam daftar pilih. Karena rencana eksekusi ditetapkan selama parsing, ini menyiratkan bahwa fungsi dalam pilih tidak dapat memengaruhinya. Kasus uji untuk memeriksa ini bisa dilakukan dengan membuat fungsi pengaturan penghitung (dalam paket atau tabel) dan membandingkan output berdasarkan di mana dalam kueri itu ditempatkan.
Chris Saxon