Collections dan Records PL/SQL

5.11. Menghindari Exception CollectionDalam banyak kasus, jika kita mereferensi elemen collection yang tidak ada, PL/SL memunculkan predefined exception. Mari kita perhatikan contoh berikut ini:

DECLARE
  TYPE NumList IS TABLE OF NUMBER;
  nums NumList; -- secara atomik null
BEGIN
  /* Assume execution continues despite the raised exceptions. */
  nums(1) := 1; -- menyebabkan COLLECTION_IS_NULL (1)
  nums := NumList(1,2); -- menginisialisasi table
  nums(NULL) := 3 -- menyebabkan VALUE_ERROR (2)
  nums(0) := 3; -- menyebabkan SUBSCRIPT_OUTSIDE_LIMIT (3)
  nums(3) := 3; -- menyebabkan SUBSCRIPT_BEYOND_COUNT (4)
  nums.DELETE(1); -- menghapus elemen 1
  IF nums(1) = 1 THEN ... -- menyebabkan NO_DATA_FOUND (5)

Di dalam kasus pertama, nested table secara atomik adalah null. Dalam kasus kedua, subscript adalah null. Dalam kasus ketiga, subscript berada di luar jangkauan yang diperbolehkan. Dalam kasus keempat, subscript melampaui jumlah elemen dalam table. Dalam kasus kelima, subscript menunjuk kepada elemen yang telah terhapus.

Daftar berikut ini menunjukkan kapan exception tertentu muncul:

Dalam beberap kasus, kita dapat melewatkan subscript-subscript yang tidak benar (invalid) kepada method tanpa menyebabkan munculnya exception. Sebagai contoh, ketika kita melewatkan subscript null kepada procedure DELETE, ia tidak melakukan apapun. Juga, kita dapat mengganti elemen-elemen yang telah terhapus tanpa memunculkan NO_DATA_FOUND, seperti ditunjukkan oleh contoh di bawah ini:

DECLARE
  TYPE NumList IS TABLE OF NUMBER;
  nums NumList := NumList(10,20,30); -- menginisialisasi table
BEGIN
  nums.DELETE(-1); -- tidak menyebabkan SUBSCRIPT_OUTSIDE_LIMIT
  nums.DELETE(3); -- menghapus elemen ke-3
  dbms_output.put_line(nums.COUNT); -- menampilkan 2
  nums(3) := 30; -- diperbolehkan; tidak menyebabkan NO_DATA_FOUND
  dbms_output.put_line(nums.COUNT); -- menampilkan 3
END;

Tipe-tipe collection ter-package dan tipe-tipe collection lokal tidak pernah kompatibel. Sebagai contoh, bayangkan kita ingin memanggil procedure ter-package berikut ini:

CREATE PACKAGE pkg1 AS
  TYPE NumList IS VARRAY(25) OF NUMBER(4);
  PROCEDURE delete_emps(emp_list NumList);
END pkg1;
CREATE PACKAGE BODY pkg1 AS
  PROCEDURE delete_emps(emp_list NumList) IS ...
  ...
END pkg1;

Ketika kita menjalankan blok PL/SQL di bawah ini, pemanggilan procedure kedua gagal dengan pesan kesalahan wrong number atau types of arguments. Hal ini dikarenakan package dan tipe-tipe VARRAY lokal tidak kompatibel meskipun definisi-definisi mereka identik.

DECLARE
  TYPE NumList IS VARRAY(25) OF NUMBER(4);
  emps pkg1.NumList := pkg1.NumList(7369, 7499);
  emps2 NumList := NumList(7521, 7566);
BEGIN
  pkg1.delete_emps(emps);
  pkg1.delete_emps(emps2); -- menyebabkan kesalahan kompilasi
END;


5.12. Mengurangi Ongkos Perulangan untuk Collections dengan Bulk Binds

Seperti ditunjukkan oleh Gambar 5-3, PL/SQL engine mengeksekusi perintah-perintah prosedural namun mengirimkan perintah-perintah SQL kepada SQL engine, yang mengeksekusi perintah-perintah SQL dan, dalam beberapa kasus, menghasilkan data untuk dikirimkan ke PL/SQL engine.

Gambar 5-3 Perpindahan Konteks

Terlalu banyak perpindahan konteks di antara PL/SQL dan SQL engine dapat membahayakan performa. Hal ini dapat terjadi ketika loop mengeksekusi perintah SQL yang terpisah untuk setiap elemen dari collection, menentukan elemen collection sebagai bind variable. Sebagai contoh, perintah DELETE berikut ini dikirimkan ke SQL engine dengan setiap iterasi dari perulangan FOR:

DECLARE
  TYPE NumList IS VARRAY(20) OF NUMBER;
  depts NumList := NumList(10, 30, 70); -- department numbers
BEGIN
  ...
  FOR i IN depts.FIRST..depts.LAST LOOP
    DELETE FROM emp
    WHERE deptno = depts(i);
  END LOOP;
END;

Dalam kasus seperti ini, jika perintah SQL mempengaruhi empat atau lebih baris-baris data pada database, penggunaan bulk binds dapat dipertimbangkan untuk meningkatkan performa.


5.12.1. Bagaimana Bulk Binds Meningkatkan Performa?

Pemberian nilai kepada variable-variable PL/SQL di dalam perintah-perintah SQL disebut binding. Operasi-operasi binding PL/SQL terbagi menjadi tiga kategori:

Perintah DML dapat mentransfer seluruh elemen-elemen dari collection dalam sebuah operasi tunggal, dan proses ini disebut dengan bulk binding. Jika collection memiliki 20 elemen, bulk binding mengijinkan kita untuk melakukan sesuatu yang sama dengan 20 perintah-perintah SELECT, INSERT, UPDATE, atau DELETE dengan menggunakan operasi tunggal. Teknik ini meningkatkan performa dengan meminimalkan jumlah perpindahan konteks di antara PL/SQL engine dan SQL engine. Dengan bulk binds, seluruh collection, tidak hanya elemen-elemen individual, dilewatkan kembali dan seterusnya.

Untuk melakukan bulk binds dengan perintah-perintah INSERT, UPDATE, dan DELETE, kita mengapit perintah SQL di dalam perintah FORALL PL/SQL.

Untuk melakukan bulk binds dengan perintah-perintah SELECT, kita menyertakan klausa BULK COLLECT di dalam perintah SELECT dibandingkan menggunakan INTO.

Contoh: Melakukan Bulk Bind dengan DELETE

Perintah DELETE berikut ini dikirimkan ke SQL engine hanya sekali, walaupun ia melakukan tiga operasi DELETE:

DECLARE
  TYPE NumList IS VARRAY(20) OF NUMBER;
  depts NumList := NumList(10, 30, 70); -- department numbers
BEGIN
  FORALL i IN depts.FIRST..depts.LAST
    DELETE FROM emp
    WHERE deptno = depts(i);
END;

Contoh: Melakukan Bulk Bind dengan INSERT

Dalam contoh di bawah ini, 5000 part number dan nama part di-load ke index-by tables. Seluruh elemen table ditambahkan ke database table sebanyak dua kali: pertama menggunakan perulangan FOR, lalu menggunakan perintah FORALL. Versi FORALL lebih cepat.

SQL> SET SERVEROUTPUT ON
SQL> CREATE TABLE parts(pnum NUMBER(4), pname CHAR(15));
Table created.
SQL> GET test.sql
1 DECLARE
2 TYPE NumTab IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER;
3 TYPE NameTab IS TABLE OF CHAR(15) INDEX BY BINARY_INTEGER;
4 pnums NumTab;
5 pnames NameTab;
6 t1 NUMBER(5);
7 t2 NUMBER(5);
8 t3 NUMBER(5);
9
10
11 BEGIN
12 FOR j IN 1..5000 LOOP -- load index-by tables
13 pnums(j) := j;
14 pnames(j) := 'Part No. '|| TO_CHAR(j);
15 END LOOP;
16 t1 := dbms_utility.get_time;
17 FOR i IN 1..5000 LOOP -- menggunakan perulangan FOR
18 INSERT INTO parts VALUES(pnums(i), pnames(i));
19 END LOOP;
20 t2 := dbms_utility.get_time;
21 FORALL i IN 1..5000 -- menggunakan perintah FORALL
22 INSERT INTO parts VALUES(pnums(i), pnames(i));
23 get_time(t3);
24 dbms_output.put_line('Execution Time (secs)');
25 dbms_output.put_line('---------------------');
26 dbms_output.put_line('FOR loop: ' || TO_CHAR(t2 - t1));
27 dbms_output.put_line('FORALL: ' || TO_CHAR(t3 - t2));
28* END;
SQL> /
Execution Time (secs)
---------------------
FOR loop: 32
FORALL: 3
PL/SQL procedure successfully completed.

 

Pages: 1 2 3 4 5 6 7 8 9 10 11 12

 

Buku ini membahas berbagai macam tip dan trik yang sangat berguna bagi Anda pembaca pengguna database Oracle. Pemula, mahasiswa, programmer, maupun database administrator yang mengharapkan solusi cepat dalam menangani permasalahan-permasalahan dalam penggunaan database Oracle dapat membaca buku ini. Anda tidak harus membaca buku ini secara urut karena buku ini di susun berdasarkan topik permasalahan, dan Anda dapat membaca topik-topik yang sesuai dengan permasalahan yang Anda hadapi.
Dapat di beli di toko buku Gramedia, Gunung Agung, Uranus, Karisma dsb. Harga Rp. 24.800,- (157 halaman)

 

Related Articles

 

Comments

[…] Silahkan melanjutkan membaca pembahasan Collections dan Records PL/SQL […]

[…] Data PL/SQL - 3,145 viewsPL/SQL Subprograms - 2,742 viewsMengontrol Akses User - 2,717 viewsCollections dan Records PL/SQL - 2,654 viewsMenampilkan Data - 2,572 viewsPendahuluan - 2,555 […]

Leave a comment

(required)

(required)


*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word