Perbedaan Trigger dan Stored Procedure MySQL

trigger dan stored procedure adalah objek database yang menyimpan logika SQL. perbedaan utamanya: trigger otomatis, procedure dipanggil manual. sebelum mempelajari ini, pastikan sudah paham cara membuat function di MySQL.
kedua fitur ini dulu sering saya anggap “canggih dan tidak perlu”, sampai ada kebutuhan mencatat setiap perubahan data di tabel secara otomatis. trigger menyelesaikannya tanpa menyentuh kode aplikasi sama sekali. sejak itu saya memahami tempatnya masing-masing: trigger untuk reaksi otomatis, procedure untuk logika yang dipanggil berulang.
1. Perbandingan Lengkap
| Aspek | Trigger | Stored Procedure |
|---|---|---|
| Dieksekusi | Otomatis (INSERT/UPDATE/DELETE) | Manual (CALL) |
| Parameter | Tidak punya parameter | IN, OUT, INOUT |
| Return value | Tidak ada | Banyak (SELECT + OUT) |
| Bisa dipanggil | Otomatis oleh event | CALL nama_procedure() |
| Jumlah per tabel | 6 tipe dasar (BEFORE/AFTER x INSERT/UPDATE/DELETE), sejak 5.7.2 bisa banyak per tipe pakai FOLLOWS/PRECEDES | Tidak terbatas |
| Transaksi | Tidak bisa COMMIT/ROLLBACK | Bisa COMMIT/ROLLBACK |
| Return result | Tidak ada | Bisa result set |
| Rekursi | Tidak bisa | Bisa (dengan hati-hati) |
| Performa | Tambah overhead per event | Hanya saat dipanggil |
2. Stored Procedure Sederhana
procedure dipanggil manual dengan CALL. cocok untuk logika yang sering dipakai berulang:
DELIMITER //
CREATE PROCEDURE insert_log(aksi VARCHAR(100))
BEGIN
INSERT INTO logs (aksi, created_at) VALUES (aksi, NOW());
END //
DELIMITER ;
penjelasan per baris:
DELIMITER //: ganti delimiter dari;jadi//sementara. perlu karena di dalam body ada statement yang diakhiri;.CREATE PROCEDURE insert_log(aksi VARCHAR(100)): bikin procedure bernamainsert_logdengan parameter inputaksivarchar 100 karakter.BEGIN ... END: blok body procedure. semua statement SQL di sini.INSERT INTO logs (aksi, created_at) VALUES (aksi, NOW()): insert ke tabel logs.NOW()fungsi bawaan untuk waktu sekarang.END //: akhir procedure, diakhiri//(delimiter baru).DELIMITER ;: kembalikan delimiter ke;(default).
cara panggil:
CALL insert_log('User login');
CALL insert_log('User logout');
3. Trigger Sederhana
trigger jalan otomatis setiap ada event di tabel. cocok untuk audit log atau update otomatis:
DELIMITER //
CREATE TRIGGER after_insert_log
AFTER INSERT ON users
FOR EACH ROW
BEGIN
INSERT INTO logs (aksi, user_id)
VALUES ('User baru', NEW.id);
END //
DELIMITER ;
penjelasan per baris:
CREATE TRIGGER after_insert_log: bikin trigger dengan namaafter_insert_log. convention: prefix dengan timing (after/before) + event.AFTER INSERT ON users: timing (AFTER) dan event (INSERT) di tabelusers. bisa juga BEFORE, UPDATE, DELETE.FOR EACH ROW: trigger jalan untuk setiap baris yang ter-insert, bukan per statement.INSERT INTO logs (aksi, user_id) VALUES ('User baru', NEW.id): insert ke tabel logs.NEW.idadalah id baris baru yang sedang di-insert ke users.NEWdanOLDadalah kata kunci khusus.NEWuntuk akses nilai baru (di INSERT/UPDATE),OLDuntuk akses nilai lama (di UPDATE/DELETE).
trigger jalan otomatis setiap ada INSERT ke tabel users. tidak perlu dipanggil manual.
4. Perbedaan NEW dan OLD
di dalam trigger, mysql sediakan dua pseudo-row untuk akses data baris yang sedang diproses:
| Event | OLD | NEW |
|---|---|---|
| INSERT | Tidak ada | Nilai baris baru |
| UPDATE | Nilai sebelum update | Nilai setelah update |
| DELETE | Nilai baris yang dihapus | Tidak ada |
contoh trigger UPDATE yang pakai keduanya:
DELIMITER //
CREATE TRIGGER after_update_user
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
INSERT INTO user_changes (user_id, old_name, new_name, changed_at)
VALUES (OLD.id, OLD.name, NEW.name, NOW());
END //
DELIMITER ;
trigger ini catat perubahan nama user ke tabel audit. OLD.name adalah nama sebelum update, NEW.name adalah nama setelah update.
5. Trigger dengan BEFORE
trigger BEFORE jalan sebelum data masuk/berubah, cocok untuk validasi atau normalisasi:
DELIMITER //
CREATE TRIGGER before_insert_user
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
-- Normalisasi email ke lowercase
SET NEW.email = LOWER(NEW.email);
-- Validasi manual: tolak email dari domain terlarang
IF NEW.email LIKE '%@spam.com' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Email dari domain spam tidak diizinkan';
END IF;
END //
DELIMITER ;
penjelasan:
SET NEW.email = LOWER(NEW.email): ubah nilaiNEW.emailsebelum di-insert. karena ini BEFORE, perubahan nilaiNEWakan dipakai untuk insert yang sebenarnya.SIGNAL SQLSTATE '45000': cara trigger melempar error. SQLSTATE 45000 artinya “unhandled user-defined exception”. procedure atau trigger akan berhenti dan rollback.SET MESSAGE_TEXT = '...': pesan error yang akan dikembalikan ke client.
6. Procedure dengan Parameter OUT
procedure bisa return nilai lewat parameter OUT, cocok untuk ambil data tanpa perlu result set:
DELIMITER //
CREATE PROCEDURE get_user_count(
IN status_user VARCHAR(20),
OUT total INT
)
BEGIN
SELECT COUNT(*) INTO total
FROM users
WHERE status = status_user;
END //
DELIMITER ;
cara panggil dari mysql cli:
CALL get_user_count('active', @total);
SELECT @total;
- parameter
IN status_user: input, dikirim dari pemanggil. - parameter
OUT total: output, diisi di dalam procedure. SELECT COUNT(*) INTO total: ambil hasil count dan simpan ke variabeltotal.@total: variabel sesi di mysql, dipakai untuk capture nilai OUT.SELECT @total: lihat hasilnya.
7. Procedure dengan INOUT
parameter INOUT gabungan: kirim nilai awal, procedure bisa modifikasi, terima nilai akhir:
DELIMITER //
CREATE PROCEDURE tambah_stok(
INOUT stok INT,
IN jumlah INT
)
BEGIN
SET stok = stok + jumlah;
END //
DELIMITER ;
panggil:
SET @stok = 100;
CALL tambah_stok(@stok, 50);
SELECT @stok; -- 150
8. Kapan Pakai Apa?
pakai stored procedure ketika:
- logika bisnis yang sama dipakai di banyak tempat (laporan, batch)
- butuh parameter input/output
- ingin sembunyikan kompleksitas SQL dari aplikasi
- perlu transaksi manual di dalam logika
pakai trigger ketika:
- butuh reaksi otomatis tanpa modify kode aplikasi
- audit log perubahan data
- validasi yang tidak bisa di-handle constraint
- update otomatis (misal update
updated_at, hitung total, sinkronisasi tabel) - pertahankan history table (soft delete pattern)
lebih baik jangan pakai keduanya ketika:
- logika bisa ditulis di kode aplikasi (lebih mudah di-test dan di-debug)
- overhead trigger/procedure jadi bottleneck performa
- tim tidak familiar dengan sql procedural (maintenance sulit)
9. Cara Hapus
hapus trigger atau procedure yang sudah tidak dipakai:
-- Hapus trigger
DROP TRIGGER IF EXISTS after_insert_log;
-- Hapus procedure
DROP PROCEDURE IF EXISTS insert_log;
IF EXISTS untuk hindari error kalau objek tidak ada. perlu privilege DROP di database.
10. Informasi Trigger dan Procedure
cara lihat daftar trigger atau procedure di database:
-- Lihat semua procedure
SHOW PROCEDURE STATUS WHERE Db = 'nama_database';
-- Lihat semua trigger
SHOW TRIGGERS;
-- Lihat source code procedure
SHOW CREATE PROCEDURE insert_log;
-- Lihat source code trigger
SHOW CREATE TRIGGER after_insert_log;
berguna untuk debug atau audit. SHOW TRIGGERS tanpa WHERE menampilkan trigger di database yang sedang aktif.
11. Performa dan Best Practice
trigger menambah overhead setiap event. beberapa tips performa:
- trigger yang kompleks (join tabel, subquery) bisa perlambat insert/update/delete. testing wajib di staging sebelum production.
- hindari recursive trigger (trigger A picu trigger B yang picu trigger A lagi). bisa deadlock.
- trigger tidak bisa di-
OPTIMIZEatau diindex terpisah. optimalkan tabel yang di-referensi. - kalau trigger error, transaksi parent otomatis rollback. pastikan trigger tidak fail untuk kasus normal.
untuk procedure:
- procedure dengan banyak statement lebih cepat di-serve dari prepared statement.
- hindari
SELECT *di dalam procedure, sebutkan kolom yang dibutuhkan. - pisah procedure panjang jadi beberapa procedure kecil yang saling panggil.
Kesimpulan
- stored procedure : dipanggil manual via
CALL, punya parameter IN/OUT/INOUT, bisa return value - trigger : otomatis jalan saat INSERT/UPDATE/DELETE, tanpa parameter, tidak bisa return
- trigger cocok untuk audit log dan sinkronisasi data otomatis
- procedure cocok untuk bisnis logic dan operasi batch yang berulang
NEWuntuk akses nilai baru,OLDuntuk nilai lama di triggerDELIMITER //wajib di body procedure/trigger yang punya banyak statementSIGNAL SQLSTATE '45000'untuk lempar error dari triggerSHOW TRIGGERSdanSHOW PROCEDURE STATUSuntuk lihat daftar- trigger menambah overhead performa, test dulu sebelum production
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Apa beda utama trigger dan stored procedure?
trigger jalan otomatis saat ada event INSERT/UPDATE/DELETE, tanpa parameter, tidak bisa return value. stored procedure dipanggil manual pakai CALL, bisa punya parameter IN/OUT/INOUT, bisa return value banyak.
Trigger bisa dipanggil manual seperti procedure?
tidak bisa. trigger hanya jalan otomatis oleh mysql saat event terjadi. kalau mau panggil manual, gunakan stored procedure atau function.
Kenapa harus pakai DELIMITER saat bikin trigger atau procedure?
karena body procedure/trigger berisi banyak statement SQL yang diakhiri titik koma. tanpa DELIMITER, mysql bingung membedakan akhir statement di dalam body dengan akhir statement CREATE PROCEDURE.
Berapa jumlah trigger maksimum per tabel?
secara tipe ada enam (BEFORE/AFTER x INSERT/UPDATE/DELETE). sebelum MySQL 5.7.2 memang maks 1 per tipe, tapi sejak 5.7.2 bisa banyak trigger per tipe yang sama, urutannya diatur pakai FOLLOWS atau PRECEDES.
Apakah trigger bisa transaksi manual?
tidak bisa COMMIT atau ROLLBACK di dalam trigger. trigger jalan dalam transaksi yang sama dengan statement yang memicunya. stored procedure sebaliknya, bisa transaksi manual.
Kapan pakai trigger dan kapan procedure?
trigger untuk reaksi otomatis (audit log, validasi, update timestamp). procedure untuk logika bisnis yang dipanggil berulang (laporan, batch process, hitung total).
Bagaimana cara hapus trigger atau procedure?
DROP TRIGGER nama_trigger; untuk hapus trigger. DROP PROCEDURE nama_procedure; untuk hapus procedure. keduanya perlu privilege DROP di database.
Apakah trigger menurunkan performa?
iya, trigger menambah overhead karena jalan setiap event. untuk query jutaan baris, ini signifikan. testing performa wajib sebelum pakai trigger di production.

