Wednesday, January 28, 2026

 Ini tipe masalah yang paling bikin curiga.

  • Tidak ada error

  • Tidak ada rollback

  • Log kelihatan normal

Tapi:

  • Server terasa berat

  • Session banyak yang aktif

  • User mulai komplain “kok lambat?”

Dan parahnya, procedure-nya kelihatan biasa saja.


Awalnya Saya Juga Mengira “Mungkin Server Lagi Sibuk”

Procedure ini jalan otomatis (job):

BEGIN process_daily_data; END;

Tidak error.
Tidak warning.
Tapi setiap jam tertentu, performa database turun.


Setelah Dicek Lebih Dalam…

Ternyata di dalam procedure ada loop seperti ini:

FOR rec IN ( SELECT order_id FROM orders WHERE status = 'NEW' ) LOOP UPDATE orders SET status = 'PROCESS' WHERE order_id = rec.order_id; END LOOP;

Sekilas:

  • Aman

  • Jelas

  • Mudah dibaca

Tapi ada masalah besar.


Masalah Utamanya: UPDATE di Dalam Loop

Kalau data:

  • 10 baris → aman

  • 100 baris → masih oke

  • 10.000 baris → mulai terasa

  • 100.000 baris → server bisa “ngap”

Kenapa?

  • Setiap loop = 1 context switch

  • Oracle harus bolak-balik SQL ↔ PL/SQL

Dan ini tidak kelihatan dari sisi error.


Versi yang Lebih Sehat

Kalau logic-nya sederhana seperti ini, loop tidak dibutuhkan.

Cukup:

UPDATE orders SET status = 'PROCESS' WHERE status = 'NEW';

Satu statement.
Lebih cepat.
Lebih ringan.


“Tapi Logic Saya Lebih Rumit…”

Nah, ini biasanya alasan kenapa loop dipertahankan.

Kalau memang perlu proses massal, pertimbangkan:

  • BULK COLLECT

  • FORALL

Contoh singkat:

SELECT order_id BULK COLLECT INTO v_ids FROM orders WHERE status = 'NEW'; FORALL i IN v_ids.FIRST .. v_ids.LAST UPDATE orders SET status = 'PROCESS' WHERE order_id = v_ids(i);

Bukan paling cantik,
tapi jauh lebih ramah performa.


Catatan Pengalaman Kerja

Saya pernah nemu job harian yang:

  • Jalan 40 menit

  • Tidak pernah error

  • Dianggap “wajar”

Setelah diubah:

  • Loop dikurangi

  • UPDATE massal diprioritaskan

Waktu turun jadi kurang dari 5 menit.

Dan tidak ada perubahan logic bisnis sama sekali.


Prinsip Pribadi Saya Sekarang

Setiap lihat PL/SQL, saya selalu cek:

  1. Ada UPDATE / INSERT di dalam loop?

  2. Bisa dijadikan satu statement SQL?

  3. Perlu loop, atau cuma kebiasaan lama?

Kalau ketemu poin 1 + data besar,
biasanya di situlah biang masalahnya.


Penutup

Procedure yang “diam” bukan berarti aman.
Kadang justru dia:

  • Pelan-pelan

  • Konsisten

  • Tapi menggerogoti resource

PL/SQL itu bukan cuma soal benar atau salah,
tapi soal dampaknya ke database.

Sampai catatan Rabu berikutnya 👋

Wednesday, January 21, 2026

 ni catatan yang muncul setelah beberapa kali “kecolongan”.

Query kelihatan rapi.
Logic kelihatan bersih.
Tapi performanya… pelan pelan banget.

Dan penyebabnya hampir selalu sama:
function PL/SQL dipanggil di dalam query.


Contoh yang Kelihatannya Aman

SELECT employee_id, get_salary_grade(salary) FROM employees;

Function get_salary_grade kelihatan sederhana.
Dan waktu dites pakai 1–2 data, tidak ada masalah.

Masalahnya baru terasa saat:

  • Datanya ribuan

  • Query dipanggil berkali-kali

  • Atau dipakai di report


Apa yang Sebenarnya Terjadi?

Oracle akan:

  • Mengambil set data

  • Lalu memanggil function untuk setiap baris

Artinya:

  • 1.000 baris → 1.000 kali function dipanggil

  • 10.000 baris → 10.000 kali function dipanggil

Kalau di dalam function ada:

  • SELECT lain

  • IF bertingkat

  • Logic tambahan

Ya jelas terasa lambat.


Contoh Function yang Jadi Masalah

FUNCTION get_salary_grade(p_salary NUMBER) RETURN VARCHAR2 IS v_grade VARCHAR2(10); BEGIN SELECT grade INTO v_grade FROM salary_grade WHERE p_salary BETWEEN min_salary AND max_salary; RETURN v_grade; END;

Secara logika: benar.
Secara performa: berbahaya kalau dipanggil massal.


Alternatif yang Lebih Aman

Daripada function di query, sering kali lebih baik:

  • Pindahkan logic ke SQL langsung

  • Pakai JOIN

Contoh:

SELECT e.employee_id, g.grade FROM employees e JOIN salary_grade g ON e.salary BETWEEN g.min_salary AND g.max_salary;

Lebih panjang sedikit,
tapi:

  • Lebih jelas

  • Lebih cepat

  • Lebih mudah dianalisis optimizer


Catatan Pengalaman Kerja

Saya pernah nemu report yang:

  • Jalan hampir 15 menit

  • Server kelihatan sibuk

  • Tidak ada error

Setelah dicek:

  • Query utamanya simpel

  • Tapi ada 2 function PL/SQL di SELECT

Begitu logic-nya dipindah ke JOIN:
👉 waktu turun jadi di bawah 1 menit

Dan lucunya, kodenya malah jadi lebih “jujur”.


Kapan Function Masih Boleh Dipakai?

Bukan berarti function itu haram 😄

Masih aman kalau:

  • Dipanggil untuk 1 record

  • Dipakai di logic procedure, bukan query massal

  • Atau benar-benar deterministic & sederhana

Yang bahaya:
👉 function + query + data besar


Penutup

Function PL/SQL itu enak dibaca.
Tapi SQL optimizer tidak peduli kode kita cantik atau tidak.

Kalau performa mulai aneh:

  • Cek dulu

  • Ada function di SELECT atau WHERE nggak?

Sering kali jawabannya: ada.

Sampai catatan Rabu berikutnya 👋

Wednesday, January 14, 2026

 Pernah ngalamin ini?

  • Query dijalankan langsung → cepat

  • Query yang sama dimasukin ke procedure → kok lama?

Awalnya saya juga mikir:

“Ah, mungkin database lagi sibuk.”

Ternyata… sering kali bukan itu masalahnya.


Kasus Nyata yang Sering Terjadi

Query ini kalau dijalankan langsung:

SELECT * FROM orders WHERE order_date >= SYSDATE - 7;

Hasilnya cepat.
Tapi begitu dimasukkan ke procedure:

CREATE OR REPLACE PROCEDURE get_orders IS CURSOR c_orders IS SELECT * FROM orders WHERE order_date >= SYSDATE - 7; v_rec c_orders%ROWTYPE; BEGIN OPEN c_orders; LOOP FETCH c_orders INTO v_rec; EXIT WHEN c_orders%NOTFOUND; -- proses data END LOOP; CLOSE c_orders; END;

Dipanggil… dan terasa lambat.


Penyebab #1: Loop Baris per Baris (Row by Row)

Ini jebakan klasik PL/SQL.

Query SQL:

  • Diproses set-based

  • Dioptimasi oleh Oracle

Loop PL/SQL:

  • Diproses baris per baris

  • Jauh lebih berat kalau datanya banyak

Di dunia PL/SQL, ini sering disebut:

“Slow by Slow”


Penyebab #2: Terlalu Banyak Logic di Dalam Loop

Kadang tanpa sadar, di dalam loop kita taruh:

  • SELECT tambahan

  • IF bertingkat

  • UPDATE per baris

Contoh jebakan:

LOOP FETCH c_orders INTO v_rec; EXIT WHEN c_orders%NOTFOUND; SELECT status INTO v_status FROM customers WHERE customer_id = v_rec.customer_id; END LOOP;

Kalau cursor berisi 10.000 baris, berarti:
👉 10.000 SELECT tambahan


Penyebab #3: Cursor Padahal Bisa SQL Murni

Banyak logic yang sebenarnya bisa ditarik ke SQL langsung.

Daripada:

  • Cursor

  • Loop

  • Logic manual

Sering kali cukup:

INSERT INTO report_table SELECT ... FROM orders o JOIN customers c ON ... WHERE ...

Lebih singkat.
Lebih cepat.
Lebih ramah performa.


Catatan Pengalaman Kerja

Di satu project lama, ada procedure yang:

  • Jalan 20 menit

  • Server kelihatan “sibuk”

Setelah dicek:

  • Ada loop

  • Di dalamnya ada SELECT

  • Di dalam SELECT ada function PL/SQL lain

Setelah diubah ke SQL murni:
👉 Waktu turun jadi kurang dari 1 menit

Dan lucunya, logic-nya jadi lebih pendek.


Prinsip yang Selalu Saya Pegang

Kalau kerja pakai PL/SQL, saya selalu tanya ke diri sendiri:

  1. Ini bisa pakai SQL saja nggak?

  2. Ini perlu loop atau cuma kebiasaan lama?

  3. Ada SELECT di dalam loop?

Kalau jawabannya “iya”, biasanya di situ sumber lambatnya.


Penutup

PL/SQL itu kuat, tapi bukan berarti semua masalah harus diselesaikan dengan loop.

Kadang:

  • Kurang kode

  • Lebih SQL
    justru hasilnya lebih baik.

Catatan berikutnya kemungkinan bahas:

  • BULK COLLECT & FORALL (versi santai, bukan textbook)

  • Atau debugging procedure yang “diam tapi makan resource”

Sampai catatan Rabu berikutnya 👋

Wednesday, January 7, 2026

Kalau dipikir-pikir, error PL/SQL itu jarang yang benar-benar “aneh”.

Yang bikin lama biasanya justru hal kecil yang terlewat.

Dan ini biasanya kejadian kalau:

  • Sudah lama nggak pegang PL/SQL

  • Atau lagi buru-buru

  • Atau merasa “ini pasti gampang”

(Spoiler: justru di situ jebakannya 😅)


1️⃣ ORA-06502: Numeric or Value Error

Ini salah satu error yang paling sering saya temui… dan paling bikin mikir.

Contoh sederhana:

DECLARE v_name VARCHAR2(5); BEGIN v_name := 'ANDI SETIAWAN'; END;

Sekilas aman.
Tapi begitu dijalankan… boom 💥

Kenapanya simpel:

  • Panjang string lebih besar dari ukuran variabel

  • Tapi saat fokus ke logika, hal kecil ini sering luput

Pelajaran:
Kalau error ini muncul, cek ukuran variabel dulu, jangan langsung nuduh query.


2️⃣ SELECT INTO yang Ternyata Balik Lebih dari Satu Baris

Ini klasik.

DECLARE v_salary NUMBER; BEGIN SELECT salary INTO v_salary FROM employees WHERE department_id = 10; END;

Di kepala kita:

“Ah, cuma satu data kok.”

Di database:

“Ini ada 5 baris, bro.”

Akhirnya:

ORA-01422: exact fetch returns more than requested number of rows

Dan biasanya baru sadar setelah:

  • Cek data manual

  • Atau ditambah ROWNUM = 1 (yang kadang cuma jadi tambalan)


3️⃣ Lupa COMMIT, Padahal Procedure Jalan Normal

Ini bukan error, tapi jebakan mental.

Procedure jalan:

  • Tidak ada error

  • Output muncul

  • Tapi data… nggak berubah

Contoh:

BEGIN UPDATE employees SET salary = salary + 1000 WHERE employee_id = 101; END;

Dijalankan, sukses.
Tapi pas dicek ulang… datanya tetap sama.

Jawabannya sederhana:
👉 belum COMMIT

Lucunya, ini sering kejadian:

  • Di environment testing

  • Saat pindah dari aplikasi ke SQL Developer


4️⃣ Error karena NULL yang Tidak Disangka

PL/SQL dan NULL itu… hubungan cinta-benci.

IF v_total = 0 THEN DBMS_OUTPUT.PUT_LINE('Kosong'); END IF;

Kalau v_total ternyata NULL, kondisi ini tidak pernah true.

Padahal di kepala kita:

“Kalau kosong ya 0 dong.”

Nope.
PL/SQL beda cerita.

Solusi paling aman:

IF NVL(v_total, 0) = 0 THEN

Catatan Pengalaman

Di satu project lama, saya pernah:

  • Ngejar error berjam-jam

  • Fokus ke query yang panjang

  • Padahal penyebabnya cuma salah ukuran VARCHAR2

Sejak itu, setiap debug PL/SQL, saya selalu mulai dari:

  1. Ukuran variabel

  2. Jumlah data SELECT INTO

  3. NULL handling

  4. COMMIT / ROLLBACK

Baru ke logika rumit.


Penutup

PL/SQL itu jarang “jahat”.
Yang sering bikin lama justru asumsi kita sendiri.

Catatan minggu ini cuma pengingat:

sebelum menyalahkan Oracle, cek dulu hal-hal kecil.

Catatan berikutnya kemungkinan bahas:

  • Procedure lambat padahal query cepat

  • Atau loop yang diam-diam bikin performa jatuh

Sampai catatan berikutnya 👋

Wednesday, December 31, 2025

 Sudah lama sekali rasanya tidak buka blog ini.

Bahkan sempat lupa terakhir nulis apa dan tahun berapa 😅

Tapi anehnya, PL/SQL itu seperti sepeda. Lama nggak dipakai, begitu disentuh lagi… pelan-pelan ingat.

Blog ini dulu saya buat cuma sebagai catatan pribadi, bukan tutorial serius. Dan sepertinya, ke depan pun akan tetap seperti itu. Catatan kecil tentang PL/SQL, error yang bikin bengong, dan solusi yang kadang kelihatannya sepele tapi nyelametin waktu berjam-jam.


Kenapa PL/SQL Masih Saya Pakai Sampai Sekarang?

Jujur, di luar sana banyak bahasa yang lebih “seksi”.
Tapi di dunia kerja, terutama yang sudah pakai Oracle bertahun-tahun, PL/SQL masih hidup dan dipakai setiap hari.

Yang sering kejadian:

  • Aplikasi baru oke

  • Tapi backend-nya tetap bergantung ke stored procedure lama

  • Dan akhirnya… kita balik lagi ke PL/SQL


Contoh Kode Sederhana (yang Sering Terlupakan)

Ini contoh kecil, tapi surprisingly sering bikin error kalau sudah lama nggak ngoding:

DECLARE v_total NUMBER; BEGIN SELECT COUNT(*) INTO v_total FROM employees; DBMS_OUTPUT.PUT_LINE('Total data: ' || v_total); END;

Kelihatannya simpel.
Tapi kesalahan yang sering saya lakukan setelah lama vakum:

  • Lupa INTO

  • Salah urutan SELECT

  • Atau lupa aktifkan DBMS_OUTPUT 😅


Catatan Pengalaman Kerja

Di satu project, saya pernah buang waktu hampir 30 menit cuma karena:

  • Procedure jalan

  • Tidak error

  • Tapi tidak ada output apa-apa

Ternyata?
Session SQL Developer-nya belum SET SERVEROUTPUT ON.

Sepele, tapi kalau lagi dikejar deadline… bisa bikin emosi.


Penutup

Blog ini akan saya hidupkan lagi, pelan-pelan tapi konsisten.
Tidak janji artikel panjang atau super rapi, tapi saya janji:

  • Kode nyata

  • Error nyata

  • Pengalaman nyata

Kalau kamu juga masih berkutat dengan PL/SQL, mungkin catatan ini bisa sedikit membantu… atau minimal bikin kamu sadar:

“Oh, ternyata bukan gue doang yang pernah salah beginian.”

Sampai catatan berikutnya.

Popular Posts