Wednesday, February 4, 2026

 Ini salah satu kebiasaan lama yang sering “lolos review”.

Procedure:

  • Jalan normal

  • Tidak error

  • Bahkan terasa aman

Padahal… dampaknya bisa panjang.


Contoh yang Sering Saya Temui

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

Secara logika:

  • Setiap data langsung disimpan

  • Kalau gagal, yang lain sudah aman

Secara sistem:
👉 ini mimpi buruk performa


Kenapa COMMIT di Loop Itu Bermasalah?

Setiap COMMIT:

  • Menulis redo log

  • Melepas undo

  • Sinkron ke disk

Kalau loop:

  • 1.000 baris → 1.000 COMMIT

  • 10.000 baris → 10.000 COMMIT

Tidak heran kalau:

  • I/O naik

  • Session lain melambat

  • Database terasa “berat”

Dan tidak ada error sama sekali.


“Tapi Saya Takut Datanya Setengah Jalan…”

Ini alasan paling sering.

Dan memang valid dalam kasus tertentu.

Tapi sebelum taruh COMMIT di loop, tanyakan dulu:

  1. Apakah datanya benar-benar besar?

  2. Apakah bisa di-rollback bersama?

  3. Apakah failure-nya sering?

Sering kali jawabannya: tidak.


Pola yang Lebih Aman

Kalau memungkinkan:

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; COMMIT;

Atau lebih baik lagi:

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

Satu commit.
Lebih bersih.
Lebih ringan.


Kapan COMMIT di Loop Masih Masuk Akal?

Ada, tapi jarang.

Biasanya kalau:

  • Proses sangat panjang (jam-an)

  • Data independen per baris

  • Failure sebagian masih bisa diterima

Dan itupun:

  • Commit per batch (misalnya tiap 1.000 baris)

  • Bukan setiap baris


Catatan Pengalaman Kerja

Saya pernah menemukan job malam yang:

  • Tidak pernah error

  • Tapi membuat backup melambat

Setelah dicek:

  • Ada COMMIT di loop

  • Data puluhan ribu

Setelah diubah:

  • Commit per batch

  • Waktu eksekusi turun drastis

  • Beban server lebih stabil


Prinsip yang Saya Pegang Sekarang

Kalau lihat:

  • COMMIT di loop
    dan

  • Data bukan kecil

Saya langsung curiga.

Bukan salah,
tapi sering tidak perlu.


Penutup

COMMIT itu penting,
tapi tempatnya juga penting.

PL/SQL bukan cuma soal “jalan atau tidak”,
tapi soal bagaimana dampaknya ke sistem.

Sampai catatan Rabu berikutnya 👋

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 👋

Popular Posts