Avoid ORM #
ORM (Object-Relational Mapping) sering dianggap sebagai silver bullet dalam pengembangan aplikasi backend. Ia menjanjikan produktivitas tinggi, kode yang rapi, dan abstraksi database yang nyaman. Namun di aplikasi skala menengah hingga besar, penggunaan ORM yang tidak terkontrol justru sering menjadi sumber utama masalah performa, beban database yang tidak perlu, dan technical debt jangka panjang.
Artikel ini membahas mengapa penggunaan ORM perlu dibatasi, dampaknya terhadap database jika digunakan secara sembarangan, serta best practice penggunaan ORM atau alternatifnya agar aplikasi tetap optimal dan scalable.
Apa Itu ORM (Secara Singkat) #
ORM adalah lapisan abstraksi yang memetakan:
- Table → Object / Struct
- Row → Instance
- Query SQL → Method / Function
Contoh ORM populer:
- Hibernate / JPA (Java)
- ActiveRecord (Rails)
- Sequelize / TypeORM (Node.js)
- GORM (Golang)
Masalahnya bukan pada ORM itu sendiri, melainkan bagaimana ORM digunakan.
Masalah Utama ORM dalam Aplikasi yang Mengejar Performa #
Query Tidak Terlihat (Hidden Query) #
ORM menyembunyikan SQL di balik method yang terlihat sederhana:
user.Preload("Orders").Preload("Items").Find(&users)
Di balik layar, ini bisa menghasilkan:
- 1 query utama
- N query relasi
- Query tambahan karena lazy loading
Developer sering tidak sadar berapa query yang benar-benar dieksekusi.
Dampak ke database:
- Lonjakan query kecil (chatty query)
- Query burst tanpa disadari
- Beban CPU dan connection pool meningkat
N+1 Query Problem (Masalah Klasik) #
Kasus umum:
- Ambil 100 user
- Untuk setiap user, ORM melakukan query ke tabel relasi
Hasilnya:
- 1 query user
- 100 query tambahan relasi
Dampak ke database:
- Query count melonjak drastis
- Latency meningkat
- DB terlihat “sibuk” padahal datanya kecil
Masalah ini tidak mungkin terjadi jika developer menulis SQL eksplisit dengan JOIN yang benar.
Overfetching Data (Ambil Data Berlebihan) #
ORM sering mendorong pola:
db.Find(&users)
Yang artinya:
SELECT * FROM users
Padahal kebutuhan API sering kali hanya:
- id
- name
- status
Dampak ke database dan network:
- Ukuran result set membengkak
- Network I/O meningkat
- Memory usage di DB dan aplikasi naik
Ini sangat berbahaya di:
- Table besar
- Kolom text / json / blob
Sulit Mengontrol Index Usage #
ORM cenderung:
- Menghasilkan query generik
- Menambahkan kondisi otomatis
- Menggunakan fungsi atau casting implisit
Contoh:
WHERE DATE(created_at) = ?WHERE LOWER(email) = ?
Dampak ke database:
- Index tidak terpakai
- Full table scan
- Query planner bekerja lebih berat
Padahal SQL manual bisa ditulis jauh lebih index-friendly.
Query Kompleks Menjadi Tidak Natural #
Ketika bisnis logic berkembang:
- Aggregation
- Window function
- Subquery
- CTE
ORM mulai terasa:
- Dipaksakan
- Tidak readable
- Lebih rumit dari SQL aslinya
Akhirnya:
- Developer tetap menulis raw SQL
- Tapi ORM masih dipakai setengah-setengah
- Arsitektur menjadi tidak konsisten
Dampak Jangka Panjang ke Database #
Jika ORM digunakan secara sembarangan:
- Database menjadi bottleneck utama
- Scaling database lebih cepat dan mahal
- Sulit melakukan query tuning
- EXPLAIN plan jarang dianalisis
- Masalah performa sulit direproduksi
Banyak kasus “database tiba-tiba lambat” ternyata bukan karena DB-nya, tetapi karena:
ORM menghasilkan query yang buruk dalam volume besar.
Kapan ORM Masih Masuk Akal Digunakan? #
ORM bukan musuh, tapi harus ditempatkan dengan tepat.
ORM masih masuk akal untuk:
- CRUD sederhana
- Table kecil
- Internal tools
- Admin panel
- Prototype / MVP
- Operasi non-critical
Dengan syarat:
- Query diaudit
- Logging query aktif
- N+1 problem dimonitor
Best Practice Menggunakan ORM (atau Menghindarinya) #
Gunakan ORM Hanya di Layer Tertentu #
Pisahkan:
- Service layer → bisnis logic
- Repository layer → data access
Di repository:
- ORM untuk query sederhana
- Raw SQL untuk query berat
Prefer Explicit Query daripada Magic ORM #
Contoh (Golang):
- ORM untuk insert/update sederhana
- Raw query untuk list, report, analytics
Ini membuat:
- Query jelas
- Mudah di-EXPLAIN
- Mudah dioptimasi
Gunakan DTO / Projection #
Jangan map hasil query langsung ke entity besar.
Gunakan struct khusus:
- Response API
- Read model
Hasilnya:
- Data lebih kecil
- Query lebih terkontrol
- Entity tidak tercemar kebutuhan API
Aktifkan Query Logging dan Monitoring #
Wajib:
- Log semua query lambat
- Monitor query count per request
- Alarm jika query tiba-tiba melonjak
Tanpa ini, ORM akan “diam-diam” menyabotase performa.
Jangan Takut Menulis SQL #
SQL adalah:
- Bahasa native database
- Paling optimal
- Paling jujur soal performa
Developer backend wajib bisa SQL, bukan hanya ORM syntax.
ORM seharusnya membantu, bukan menggantikan pemahaman database.
Pendekatan Alternatif yang Lebih Scalable #
Banyak tim besar memilih:
Hybrid approach
- ORM untuk write sederhana
- SQL manual untuk read-heavy
Query Builder ringan
- Lebih eksplisit dari ORM
- Lebih aman dari raw string
CQRS ringan
- Write model ≠ Read model
Pendekatan ini terbukti:
- Lebih predictable
- Lebih mudah di-scale
- Lebih ramah database
Penutup #
ORM bukan masalah — penggunaan ORM tanpa kontrol adalah masalah.
Jika aplikasi Anda:
- Mulai lambat tanpa sebab jelas
- Database cepat penuh beban
- Query sulit dianalisis
Maka sangat besar kemungkinan:
ORM digunakan terlalu jauh dari batas idealnya.
Gunakan ORM dengan sadar, pahami SQL di baliknya, dan jangan ragu turun ke level database ketika performa menjadi prioritas.
Karena pada akhirnya:
Aplikasi cepat lahir dari query yang jujur, bukan abstraksi yang terlalu nyaman.