Kenapa Menggunakan Enum pada Tipe Kolom Database
7 min read

Kenapa Menggunakan Enum pada Tipe Kolom Database

Dalam desain database relasional, pemilihan tipe kolom sering dianggap detail kecil, padahal dampaknya bisa besar terhadap konsistensi data, performa query, kemudahan maintenance, dan keterbacaan sistem secara keseluruhan. Salah satu keputusan desain yang sering diperdebatkan adalah: apakah nilai tertentu sebaiknya disimpan sebagai string biasa, atau menggunakan enum?

Artikel ini akan membahas secara mendalam kenapa enum sering menjadi pilihan yang baik, bagaimana cara kerjanya di level database dan aplikasi, serta trade-off dan best practice agar penggunaannya tidak menjadi jebakan di kemudian hari.


Apa Itu Enum dalam Konteks Database?

Enum (enumeration) adalah tipe data yang merepresentasikan sekumpulan nilai terbatas dan terdefinisi. Contoh klasik:

  • status user: ACTIVE, INACTIVE, BANNED
  • status order: PENDING, PAID, SHIPPED, CANCELLED
  • role: ADMIN, USER, MODERATOR

Secara konsep, enum menyatakan bahwa:

Kolom ini hanya boleh berisi nilai-nilai tertentu, tidak lebih, tidak kurang.

Implementasinya bisa berbeda-beda:

  • Native enum database (MySQL ENUM, PostgreSQL ENUM)
  • Enum berbasis integer (smallint/int + mapping di aplikasi)
  • Lookup table (foreign key ke tabel referensi)

Artikel ini fokus pada pendekatan enum berbasis integer dengan representasi teks karena paling umum dan fleksibel di sistem skala besar.


Cara Kerja Enum Berbasis Integer

Representasi di Storage

Pada pendekatan ini:

Nilai LogisNilai Tersimpan
ACTIVE1
INACTIVE2
BANNED3

Yang disimpan di database adalah integer, bukan string.

Representasi di Aplikasi

Di aplikasi:

  • Backend memetakan integer → enum
  • Frontend / API response mengirimkan teks enum, bukan angka mentah

Contoh:

{
  "status": "ACTIVE"
}

Dengan demikian:

  • Database optimal
  • API tetap human-friendly

Alasan Utama Menggunakan Enum di Kolom

1. Lebih Optimal untuk Index dan Query

  • Integer:

    • Fixed size (1–4 byte)
    • Perbandingan sangat cepat (CPU-friendly)
  • String:

    • Variable length
    • Perbandingan byte-per-byte

Akibatnya:

  • Index berbasis integer lebih kecil
  • Lebih banyak index page bisa masuk ke memory
  • Query dengan WHERE, JOIN, GROUP BY lebih efisien

Contoh:

SELECT * FROM orders WHERE status = 2;

Ini jauh lebih murah dibanding:

SELECT * FROM orders WHERE status = 'SHIPPED';

2. Konsistensi Data Terjamin

Tanpa enum:

  • active
  • Active
  • ACTIVE
  • actve (typo)

Dengan enum:

  • Hanya nilai yang diizinkan sistem yang bisa masuk
  • Tidak ada variasi liar atau typo

Ini penting terutama pada:

  • Sistem besar
  • Banyak service
  • Banyak developer

Enum berfungsi sebagai kontrak data.

3. Lebih Mudah Dipahami di Level Domain

Enum merepresentasikan business concept, bukan sekadar data mentah.

Contoh di code:

type OrderStatus int

const (
    OrderPending OrderStatus = 1
    OrderPaid    OrderStatus = 2
    OrderShipped OrderStatus = 3
)

Dibandingkan:

if status == 3 { ... }

Enum membuat code:

  • Lebih eksplisit
  • Lebih self-documenting
  • Lebih sulit disalahgunakan

4. Hasil Query Tetap Human-Friendly

Walaupun disimpan sebagai integer, enum tidak harus tampil sebagai angka.

Opsi 1: Mapping di Aplikasi

Backend mengubah:

  • 2PAID

Opsi 2: CASE / JOIN di SQL

SELECT
  CASE status
    WHEN 1 THEN 'PENDING'
    WHEN 2 THEN 'PAID'
    WHEN 3 THEN 'SHIPPED'
  END AS status
FROM orders;

Hasil query tetap mudah dibaca oleh:

  • Developer
  • Analyst
  • Support

5. Lebih Hemat Storage

Perbandingan kasar:

TipeEstimasi Size
INT4 byte
VARCHAR(20)hingga 20+ byte

Pada tabel besar (jutaan baris):

  • Penghematan storage signifikan
  • Index jauh lebih ramping
  • Cache hit ratio meningkat

6. Lebih Aman untuk Refactor dan Rename

Bayangkan:

  • WAITING_PAYMENT diubah jadi UNPAID

Jika disimpan sebagai string:

  • Update jutaan row
  • Risiko typo
  • Downtime

Jika enum integer:

  • Angka tetap sama
  • Hanya mapping text yang berubah

Ini membuat refactor jauh lebih aman.


Perbandingan dengan Lookup Table

AspekEnum IntegerLookup Table
Join tambahan
PerformaSangat cepatLebih lambat
Fleksibilitas runtimeRendahTinggi
Cocok untukNilai stabilNilai dinamis

Rule of thumb:

  • Nilai jarang berubah → enum
  • Nilai sering berubah / user-defined → lookup table

Apa yang Terjadi Jika Menambah Entry Enum pada Data yang Sudah Besar?

Menambah nilai enum terlihat sepele, tetapi pada sistem dengan data besar (jutaan baris, banyak service, banyak consumer), ini adalah salah satu sumber bug dan insiden produksi yang paling sering diremehkan.

Berikut hal-hal penting yang perlu dipahami dan diwaspadai.

1. Dampak di Level Database

Jika menggunakan enum berbasis integer:

  • Tidak ada perubahan data existing
  • Tidak perlu update jutaan row
  • Index tetap valid
  • Performa relatif aman

Contoh:

EnumNilai
PENDING1
PAID2
SHIPPED3
CANCELLED4← enum baru

Secara database:

  • Hanya menambah makna baru
  • Angka lama tidak berubah

⚠️ Bahaya besar terjadi jika:

  • Mengubah nilai integer enum lama
  • Menyisipkan enum di tengah (bukan di akhir)

Ini bisa menyebabkan:

  • Data lama berubah makna
  • Bug silent (tidak error, tapi salah logika)

2. Perbedaan dengan Native ENUM Database

Jika menggunakan native ENUM (misalnya MySQL ENUM atau PostgreSQL ENUM):

  • Menambah enum = ALTER TYPE / ALTER TABLE

  • Operasi ini bisa:

    • Mengunci tabel (tergantung DB & versi)
    • Memakan waktu lama pada tabel besar

Contoh di PostgreSQL:

ALTER TYPE order_status ADD VALUE 'CANCELLED';

Pada tabel besar:

  • Bisa blocking write
  • Berisiko di jam sibuk

Inilah alasan banyak sistem skala besar menghindari native ENUM dan memilih integer + mapping.

3. Dampak di Aplikasi & Microservices

Masalah paling umum bukan di database, tapi di aplikasi.

Jika enum baru ditambahkan:

  • Service A sudah tahu
  • Service B belum deploy

Akibatnya:

  • Service lama menerima nilai enum yang tidak dikenal

  • Bisa terjadi:

    • Panic / exception
    • Default branch salah
    • Logic bisnis bocor

Contoh berbahaya:

switch status {
case OrderPending:
case OrderPaid:
case OrderShipped:
    // ok
}
// tidak ada default

Saat enum baru muncul → undefined behavior.

4. Backward Compatibility adalah Kunci

Setiap penambahan enum harus dianggap sebagai:

Breaking change potensial

Best practice:

  • Selalu sediakan default / UNKNOWN

  • Logic lama harus bisa:

    • Mengabaikan enum baru
    • Atau memperlakukannya sebagai safe fallback

Contoh:

const (
    OrderUnknown OrderStatus = 0
    OrderPending OrderStatus = 1
    OrderPaid    OrderStatus = 2
    OrderShipped OrderStatus = 3
    OrderCancelled OrderStatus = 4
)

Dengan ini:

  • Service lama tidak crash
  • Sistem tetap stabil

5. Dampak ke Data Analytics & Reporting

Enum baru sering berdampak ke:

  • Dashboard
  • Report
  • Query BI

Jika tidak diantisipasi:

  • Grafik tidak konsisten
  • Data terlihat “hilang”
  • Aggregation salah

Contoh:

SELECT status, COUNT(*) FROM orders GROUP BY status;

Enum baru bisa:

  • Tidak terpetakan di dashboard
  • Tidak punya label

Solusi:

  • Update mapping analytics bersamaan
  • Dokumentasikan perubahan enum

6. Deployment Strategy yang Aman

Untuk sistem besar, urutan aman:

  1. Deploy aplikasi yang toleran enum baru
  2. Pastikan fallback logic aktif
  3. Baru mulai menulis data dengan enum baru

❌ Jangan langsung:

  • Menulis enum baru
  • Saat sebagian service belum siap

Ini sering menyebabkan incident lintas service.


Ringkasan Risiko Utama

RisikoPenyebab
Data salah maknaMengubah nilai enum lama
Service crashEnum baru tidak dikenali
DowntimeALTER ENUM di tabel besar
Bug silentTidak ada default handling

Kapan Enum Tidak Disarankan?

Enum bukan solusi universal.

Hindari enum jika:

  • Nilai sering berubah oleh admin
  • Perlu ditambah tanpa deploy ulang
  • Jumlah nilai sangat besar
  • Nilai bersifat konfigurasi, bukan domain tetap

Dalam kasus ini, lookup table lebih tepat.


Kesalahan Umum (Kesalahan Fatal dalam Penggunaan Enum)

Banyak tim menyimpulkan bahwa “enum itu buruk” bukan karena konsepnya salah, tetapi karena kesalahan implementasi berikut. Di sistem besar, kesalahan-kesalahan ini hampir selalu berujung incident.

1. Mengubah Nilai Integer Enum yang Sudah Dipakai

Ini adalah kesalahan paling fatal.

PAID = 2  → diubah jadi 5

Dampaknya:

  • Data lama langsung berubah makna
  • Tidak ada error
  • Bug bersifat silent dan sangat sulit dilacak

Rule keras:

Nilai integer enum tidak boleh berubah selamanya.

2. Menyisipkan Enum di Tengah, Bukan di Akhir

Contoh buruk:

EnumNilai
PENDING1
PAID2
CANCELLED3← disisipkan
SHIPPED4

Jika data lama sudah memakai 3 = SHIPPED, maka:

  • Makna data historis rusak
  • Report dan analytics salah total

Best practice:

  • Enum baru selalu ditambahkan di akhir

3. Tidak Menyediakan Default / UNKNOWN State

Tanpa fallback:

switch status {
case OrderPending:
case OrderPaid:
case OrderShipped:
}

Saat enum baru muncul:

  • Panic
  • Logic lompat
  • Atau state tidak ter-handle

Solusi wajib:

const (
    OrderUnknown OrderStatus = 0
    OrderPending OrderStatus = 1
    OrderPaid    OrderStatus = 2
    OrderShipped OrderStatus = 3
)

Enum baru tidak langsung mematikan service lama.

4. Menulis Enum Baru Sebelum Semua Service Siap

Pada arsitektur microservices:

  • Service A sudah deploy
  • Service B masih versi lama
  • Database mulai menyimpan enum baru

Akibatnya:

  • Service lama menerima nilai tidak dikenal
  • Error lintas service

Urutan yang benar:

  1. Deploy service yang toleran enum baru
  2. Pastikan fallback logic aktif
  3. Baru mulai menulis enum baru

5. Menggunakan Native ENUM di Tabel Besar Tanpa Strategi

Native ENUM terlihat rapi, tapi:

  • ALTER TYPE / ALTER TABLE
  • Bisa locking
  • Berisiko downtime

Ini sering terjadi di:

  • MySQL ENUM
  • PostgreSQL ENUM

Untuk sistem besar:

  • Lebih aman integer + mapping

6. Menganggap Enum Sebagai Konfigurasi

Kesalahan desain:

  • Enum dipakai untuk nilai yang sering berubah
  • Harus deploy hanya untuk tambah opsi

Tanda enum salah pakai:

  • Sering diminta “tolong tambahin value”
  • Tidak jelas domain-nya

Dalam kasus ini:

  • Gunakan lookup table

Ringkasan Kesalahan Fatal

KesalahanDampak
Ubah nilai enum lamaData rusak tanpa error
Sisip enum di tengahMakna historis berubah
Tidak ada UNKNOWNService crash
Tidak backward compatibleIncident lintas service
Native ENUM tanpa strategiDowntime

Best Practice Penggunaan Enum

  1. Gunakan integer sebagai storage
  2. Jangan ubah nilai numerik enum yang sudah dipakai
  3. Tambah enum baru di akhir
  4. Mapping enum wajib konsisten di semua service
  5. Dokumentasikan enum sebagai bagian dari domain model

Penutup

Enum pada kolom database bukan sekadar preferensi gaya, melainkan keputusan arsitektural yang berdampak langsung pada:

  • Performa
  • Konsistensi data
  • Kualitas code
  • Kemudahan maintenance jangka panjang

Dengan menyimpan enum sebagai integer yang direpresentasikan sebagai teks di aplikasi, kita mendapatkan kombinasi terbaik dari dua dunia: efisiensi mesin dan keterbacaan manusia.

Jika digunakan dengan tepat dan disiplin, enum adalah salah satu senjata paling sederhana namun powerful dalam desain sistem backend.