Database Roundtrip

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:

  1. Aplikasi mengirim query ke database
  2. Query melewati network (TCP)
  3. Database mem-parse, optimize, dan mengeksekusi query
  4. Database mengirim hasil kembali ke aplikasi
  5. 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.

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact