Database Roundtrip #
Dalam banyak kasus performa aplikasi yang melambat, masalahnya bukan pada database engine yang lambat, CPU penuh, atau query yang “jelek” secara sintaks. Salah satu penyebab yang sering luput dari perhatian adalah database roundtrip.
Roundtrip tidak selalu terlihat di EXPLAIN plan, tidak selalu terlihat di slow query log, namun akumulatif dampaknya sangat besar, terutama pada sistem dengan traffic tinggi, microservices, atau backend yang banyak melakukan query kecil.
Artikel ini akan membedah:
- Apa itu database roundtrip
- Kenapa roundtrip sangat mahal
- Bagaimana roundtrip mempengaruhi performa query & sistem
- Contoh kasus nyata
- Best practice untuk mengurangi database roundtrip
Apa Itu Database Roundtrip? #
Database roundtrip adalah satu siklus penuh komunikasi antara aplikasi dan database, yang terdiri dari:
- Aplikasi mengirim query ke database
- Query melewati network (TCP)
- Database mem-parse, optimize, dan mengeksekusi query
- Database mengirim hasil kembali ke aplikasi
- Aplikasi menerima dan memproses hasil
Setiap satu query = minimal satu roundtrip.
🔑 Intinya: Roundtrip bukan hanya soal eksekusi SQL, tapi juga latency jaringan, context switching, dan overhead protocol.
Kenapa Database Roundtrip Itu Mahal? #
Network Latency Tidak Pernah Nol #
Walaupun database dan aplikasi berada di:
- VM yang sama
- VPC yang sama
- Bahkan AZ yang sama
Tetap ada latency:
- TCP handshake & buffering
- Kernel context switch
- Serialization / deserialization data
Latensi ini mungkin hanya 0.5–2 ms, tapi:
1 query = 1–2 ms
100 query = 100–200 ms
1000 query = 1–2 detik
Tanpa sadar, aplikasi terasa “lambat” padahal tiap query cepat.
Overhead Parsing & Planning di Database #
Setiap query:
- Di-parse
- Dibuat execution plan
- Dialokasikan resource
Walaupun query sederhana:
SELECT name FROM users WHERE id = ?;
Tetap memerlukan:
- CPU untuk parsing
- Memory untuk plan
- Lock internal
Semakin banyak roundtrip → semakin banyak overhead internal DB.
Context Switching & Connection Handling #
Pada RDBMS modern:
- Setiap query melibatkan worker thread / process
- Ada context switching OS
- Ada mutex & lock internal
1000 query kecil lebih mahal daripada 1 query besar.
Dampak Database Roundtrip Terhadap Performa #
Latency Aplikasi Meledak #
Contoh klasik:
User request
├─ Query user
├─ Query profile
├─ Query address
├─ Query orders
├─ Query order_items
└─ Query payments
Total: 6 roundtrip
Jika masing-masing 10 ms:
6 × 10 ms = 60 ms (hanya DB)
Tambahkan logic aplikasi, network, JSON, dll → mudah tembus ratusan ms.
N+1 Query Problem #
Contoh:
SELECT * FROM orders WHERE user_id = 10;
Lalu untuk setiap order:
SELECT * FROM order_items WHERE order_id = ?;
Jika ada 100 order:
- 1 query ambil orders
- 100 query ambil items
➡️ 101 database roundtrip
Ini salah satu penyebab performa paling umum di aplikasi backend.
Database Terlihat “Normal”, Tapi Sistem Lambat #
Gejala klasik:
- CPU DB rendah
- Memory aman
- Query individual cepat
- Tapi latency API tinggi
Penyebabnya:
- Terlalu banyak query kecil
- Terlalu banyak roundtrip
- Network I/O meningkat
Contoh Kasus Nyata #
Kasus: API Response 8 Detik, Query Aman #
- Query rata-rata: < 5 ms
- Tidak ada slow query
- CPU DB < 30%
- Network I/O DB tinggi
Setelah tracing:
- Satu request API melakukan 400+ query kecil
- Total waktu habis di latency roundtrip
Solusi:
- Gabungkan query
- Gunakan JOIN
- Kurangi query di loop
Hasil:
- Query count turun dari 400 → 12
- Response time turun dari 8 detik → 300 ms
Best Practice Mengurangi Database Roundtrip #
Gabungkan Query (Batching) #
❌ Buruk:
SELECT * FROM users WHERE id = 1;
SELECT * FROM users WHERE id = 2;
SELECT * FROM users WHERE id = 3;
✅ Baik:
SELECT * FROM users WHERE id IN (1,2,3);
Satu query, satu roundtrip.
Gunakan JOIN dengan Bijak #
❌ Banyak roundtrip:
SELECT * FROM users WHERE id = 1;
SELECT * FROM profiles WHERE user_id = 1;
✅ Lebih efisien:
SELECT u.*, p.*
FROM users u
JOIN profiles p ON p.user_id = u.id
WHERE u.id = 1;
Catatan: JOIN jauh lebih murah daripada extra roundtrip.
Hindari Query di Dalam Loop #
❌ Anti-pattern:
for _, id := range userIDs {
db.Query("SELECT * FROM users WHERE id = ?", id)
}
✅ Perbaikan:
SELECT * FROM users WHERE id IN (...);
Gunakan Eager Loading (ORM) #
Jika menggunakan ORM:
- Aktifkan eager loading
- Hindari lazy loading default
Contoh konsep:
Load user + orders + items dalam satu query
bukan query terpisah
Caching untuk Data Read-Heavy #
- Redis / Memcached
- Local in-memory cache
Menghindari roundtrip DB sama sekali jauh lebih baik.
Perhatikan Payload Result #
Roundtrip bukan hanya jumlah query, tapi juga:
- Ukuran data
- Jumlah kolom
❌ Buruk:
SELECT * FROM big_table;
✅ Lebih baik:
SELECT id, name FROM big_table;
Lebih kecil payload → lebih cepat roundtrip.
Mental Model yang Perlu Diingat #
❗ Database lebih suka bekerja keras sekali daripada bolak-balik berbicara dengan aplikasi.
- 1 query kompleks ❌ tidak selalu buruk
- Banyak query kecil ✅ sering lebih buruk
Optimasi roundtrip sering memberi dampak lebih besar daripada optimasi index.
Penutup #
Database roundtrip adalah silent performance killer:
- Tidak terlihat jelas
- Tidak selalu muncul di log
- Tapi sangat terasa di latency
Dengan:
- Mengurangi jumlah query
- Menghindari N+1
- Menggabungkan data secara cerdas
Anda bisa mendapatkan lonjakan performa besar tanpa mengubah database engine atau hardware.
Jika API terasa lambat padahal DB terlihat sehat, hitung jumlah query per request — kemungkinan besar jawabannya ada di sana.