Mengapa menggunakan kursor eksplisit, bukan loop biasa?

12

Saya telah menulis aplikasi web dasar selama setahun (untuk Oracle db), dan karena fungsinya cukup sederhana, kebanyakan dari kita tetap menggunakan loop FOR reguler untuk mendapatkan data kami:

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

Tapi, kursor tampaknya menjadi cara yang 'tepat' untuk melakukan sesuatu. Saya dapat menemukan banyak informasi tentang kursor apa dan berbagai cara untuk mengulanginya, tetapi saya tidak dapat menemukan alasan yang kuat mengapa menggunakannya pada loop FOR reguler. Apakah ini tergantung pada kebutuhan prosedur? Apakah ada keuntungan yang melekat yang harus saya waspadai?

ini
sumber
Jenis FORini hanyalah cara lain untuk menggunakan kursor. Lihat dokumen: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… Pokoknya, apa yang htp.prn () lakukan?
dezso
Itu salah satu fungsi output kami. Jadi, apakah Anda memiliki preferensi tentang metode mana yang digunakan?
ini
Untuk hal-hal seperti ini, FORperulangannya jauh lebih mudah dibaca, saya pikir. Saya cenderung menggunakan kursor 'asli' hanya jika saya harus mundur, tidak hanya ke depan. Saya mengajukan pertanyaan lain karena saya bisa membayangkan fungsi tabel, bukan htp.prn().
dezso
Perlu disebutkan bahwa kedua bentuk kursor memiliki kinerja yang lebih rendah daripada solusi SQL murni - khususnya yang relevan dengan pernyataan DML.
David Aldridge

Jawaban:

7

Kursor dapat menjadi eksplisit atau implisit, dan salah satu tipe dapat digunakan dalam loop FOR. Sebenarnya ada dua aspek dari pertanyaan Anda.

  1. Mengapa menggunakan loop FOR kursor eksplisit di atas kursor implisit FOR loop?

    • Gunakan loop FOR kursor eksplisit ketika kueri akan digunakan kembali, jika tidak kursor implisit lebih disukai.
  2. Mengapa menggunakan loop dengan FETCH daripada loop UNTUK yang tidak memiliki FETCH eksplisit?

    • Gunakan FETCH di dalam loop ketika Anda perlu mengumpulkan massal atau ketika Anda membutuhkan SQL dinamis.

Berikut ini beberapa informasi berguna dari dokumentasi.

Contoh Kursor Tersirat UNTUK LOOP

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Contoh Kursor Eksplisit UNTUK LOOP

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Kursor Tersirat

Kursor implisit adalah kursor sesi yang dibangun dan dikelola oleh PL / SQL. PL / SQL membuka kursor implisit setiap kali Anda menjalankan pernyataan SELECT atau DML. Anda tidak dapat mengontrol kursor implisit, tetapi Anda bisa mendapatkan informasi dari atributnya.

Kursor implisit ditutup setelah pernyataan terkait berjalan; namun, nilai atributnya tetap tersedia hingga pernyataan SELECT atau DML lainnya berjalan.

Atribut kursor implisit adalah: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

Kursor Eksplisit

Kursor eksplisit adalah kursor sesi yang Anda buat dan kelola. Anda harus mendeklarasikan dan menetapkan kursor eksplisit, memberinya nama dan mengaitkannya dengan kueri (biasanya, kueri mengembalikan beberapa baris). Kemudian Anda dapat memproses hasil kueri yang diatur dalam salah satu dari cara berikut:

Buka kursor eksplisit (dengan pernyataan OPEN), ambil baris dari set hasil (dengan pernyataan FETCH), dan tutup kursor eksplisit (dengan pernyataan TUTUP).

Gunakan kursor eksplisit dalam pernyataan kursor UNTUK LOOP (lihat "Hasil Kueri Mengatur Pemrosesan Dengan Kursor Untuk Pernyataan LOOP").

Anda tidak dapat menetapkan nilai ke kursor eksplisit, menggunakannya dalam ekspresi, atau menggunakannya sebagai parameter subprogram formal atau variabel host. Anda dapat melakukan hal-hal itu dengan variabel kursor (lihat "Variabel Kursor").

Tidak seperti kursor implisit, Anda dapat mereferensikan kursor eksplisit atau variabel kursor dengan namanya. Oleh karena itu, variabel kursor atau kursor eksplisit disebut kursor bernama.

Kursor UNTUK Pernyataan LOOP

Pernyataan kursor UNTUK LOOP memungkinkan Anda menjalankan pernyataan SELECT dan kemudian segera loop melalui baris set hasil. Pernyataan ini dapat menggunakan kursor implisit atau eksplisit.

Leigh Riffel
sumber
1
Kursor implisit mengambil 100 baris sekaligus dari 10g dan seterusnya.
David Aldridge
16

Kode yang Anda poskan menggunakan kursor. Itu menggunakan loop kursor implisit.

Ada kasus di mana menggunakan loop kursor eksplisit (yaitu mendeklarasikan variabel CURSOR di bagian deklarasi) menghasilkan kode pembersih atau kinerja yang lebih baik

  1. Jika Anda memiliki kueri yang lebih rumit yang tidak dapat Anda refaktikan menjadi tampilan, ini dapat membuat kode lebih mudah dibaca jika perulangan Anda berulang student_cursordaripada menyertakan pernyataan SQL 30 baris yang menyematkan banyak logika. Misalnya, jika Anda mencetak semua siswa yang telah lulus dan yang bergabung dengan tabel yang memiliki catatan akademik mereka, persyaratan program gelar mereka, tabel dengan informasi tentang ruang akademik, tabel dengan informasi tentang buku perpustakaan yang sudah lewat, tabel dengan informasi tentang biaya yang belum dibayar, penggantian administratif, dll. mungkin akan masuk akal untuk memperbaiki kode sehingga kueri ini tidak macet di tengah-tengah kode yang berkaitan dengan penyajian daftar kepada pengguna. Itu mungkin melibatkan membuat tampilan yang akan merangkum semua logika ini. Atau mungkin melibatkan membuat kursor eksplisit yang dinyatakan baik sebagai bagian dari blok PL / SQL saat ini atau di beberapa blok PL / SQL level yang lebih tinggi (yaitu kursor dideklarasikan dalam sebuah paket) sehingga dapat digunakan kembali. Atau mungkin melibatkan melakukan sesuatu yang lain untuk enkapsulasi dan penggunaan kembali (katakanlah, membuat fungsi tabel pipelined sebagai gantinya).
  2. Jika Anda ingin menggunakan operasi massal dalam PL / SQL, Anda umumnya ingin menggunakan kursor eksplisit. Berikut adalah utas StackOverflow yang membahas perbedaan kinerja antara kursor eksplisit dan implisit . Jika semua yang Anda lakukan adalah menelepon htp.prn, melakukan BULK COLLECTmungkin tidak membeli apa pun untuk Anda. Namun, dalam kasus lain, ini dapat menghasilkan peningkatan kinerja yang substansial.
Gua Justin
sumber
2

Saya melihat bahwa banyak pengembang menggunakan kursor eksplisit dan bukan kursor implisit karena kebiasaan lama. Ini karena di Oracle versi 7 ini selalu merupakan cara yang lebih efisien. Saat ini umumnya ada sebaliknya. Khususnya dengan pengoptimal bahwa jika diperlukan dapat menulis ulang kursor implisit untuk loop ke pengumpulan massal.

Peter Åkerlund
sumber
0

Baru-baru ini saya harus menulis ulang banyak pertanyaan dari loop FOR implisit ke dalam kursor eksplisit. Alasannya adalah bahwa kueri mengambil data dari basis data eksternal melalui tautan dan basis data ini memiliki penyandian yang berbeda dari basis data lokal kami. Saat mentransfer data dari kursor implisit ke tipe record yang ditentukan secara lokal, kesalahan intermiten yang terjadi terjadi (hanya pada baris tertentu tertentu). DBA kami menjelaskan hal ini kepada kami, kami tidak akan bisa sampai ke dasar ini sendiri. Sepertinya ini adalah bug di Oracle yang telah dilaporkan.

Kami disarankan untuk menulis ulang semuanya menggunakan kursor eksplisit dan kesalahan telah hilang.

Bukan alasan utama Anda mungkin ingin menggunakan eksplisit daripada implisit, tetapi layak dicatat.

EDIT: Oracle 12c.

Robotron
sumber
Bisakah Anda menambahkan bug dan / atau nomor note sehingga mereka yang membaca ini dapat mengetahui lebih banyak tentang gejala dan jika / ketika ini diselesaikan?
Leigh Riffel
Maaf, pelaporan bug dilakukan oleh salah satu DBA kami, saya tidak memiliki akses ke informasi itu.
Robotron