Menjawab Masalah Query Lambat Go Fiber
Query Lambat Go Fiber umumnya disebabkan oleh Postgres harus memindai tabel besar tanpa indeks yang sesuai, atau karena pagination dengan OFFSET yang meningkatkan biaya baca saat data tumbuh. Artikel ini menjelaskan langkah konkret untuk menemukan dan memperbaiki bottleneck, memilih index yang tepat, serta memanfaatkan pagination berbasis keyset agar performa query tetap konsisten.
Dalam waktu singkat Anda akan belajar membaca EXPLAIN ANALYZE, menentukan bila composite/partial/covering index paling sesuai, serta menulis handler Go Fiber yang menggunakan GORM atau database/sql untuk paging yang tetap memanfaatkan index saat volume data membesar. Serta menyertakan cara monitoring sederhana untuk memastikan index digunakan.
Identifikasi Bottleneck dengan EXPLAIN ANALYZE
EXPLAIN ANALYZE menjalankan query dan memberikan estimasi serta waktu eksekusi nyata agar kita tahu apakah query melakukan seq scan, index scan, atau nested loop yang mahal. Pastikan query yang Anda lihat di handler Fiber dijalankan langsung di Postgres untuk mendapatkan hasil aktual.
Cara Menggunakan EXPLAIN ANALYZE
Jalankan seperti berikut pada query yang bermasalah: EXPLAIN ANALYZE SELECT .... Fokus perhatikan kolom Plan Rows dan Actual Loops. Jika query melakukan Seq Scan pada tabel besar, saatnya menambahkan index. Jika waktu eksekusi panjang karena Bitmap Heap Scan, pertimbangkan index lain atau rewrite filter.
Menginterpretasi Output
Perhatikan juga Buffers dan I/O jika Anda menyalakan statistik buffer. Jika banyak cache yang digunakan tapi tetap lambat, mungkin data tidak menggunakan index. Catat kondisi parameter query (misalnya variabel filter) karena query parametrik bisa menyebabkan generic plan yang tidak optimal.
Memilih Index yang Tepat di Postgres
Index yang tepat tergantung pola filtrasi. Ada tiga tipe utama yang sering jadi jawaban untuk query Go Fiber: composite index untuk kombinasi kolom, partial index saat filter tertentu sering muncul, dan covering index untuk menghindari heap fetch.
Composite Index
Gunakan composite index ketika query selalu menggunakan beberapa kolom dalam WHERE atau ORDER BY. Pastikan urutan kolom mencerminkan urutan filter dan sort. Contoh: CREATE INDEX ON orders (user_id, created_at DESC) untuk query yang menyaring user_id dan mengurutkan tanggal.
Partial Index
Jika query sering menarget baris dengan kondisi tetap (misal status = 'pending'), partial index mengurangi ukuran indeks. Contoh: CREATE INDEX ON orders (user_id, created_at) WHERE status = 'pending'. Ini membantu Postgres menggunakan index hanya untuk subset relevan dan menjadikan EXPLAIN ANALYZE menampilkan Index Scan kecil.
Covering Index
Menambahkan kolom yang hanya dibutuhkan query ke bagian INCLUDE memungkinkan Postgres menjawab query langsung dari index tanpa mengakses tabel. Contoh: CREATE INDEX ON orders (user_id, created_at) INCLUDE (total_amount). Ini mempercepat query select yang hanya membutuhkan kolom-kolom tersebut.
Pagination Efisien: Offset vs Keyset
Offset pagination bekerja walau sederhana, namun semakin besar offset, semakin banyak Postgres mengabaikan baris awalnya. Keyset pagination (juga dikenal sebagai cursor pagination) menggunakan nilai terakhir dari halaman sebelumnya agar query tetap memanfaatkan index.
Implementasi Keyset di Go Fiber
Contoh handler menggunakan database/sql:
func listOrders(c *fiber.Ctx) error {
db := c.Locals("db").(*sql.DB)
lastCreated := c.Query("after")
var rows *sql.Rows
var err error
if lastCreated == "" {
rows, err = db.Query(`SELECT id, created_at, total_amount FROM orders
WHERE user_id = $1
ORDER BY created_at DESC
LIMIT 20`, c.Query("user_id"))
} else {
rows, err = db.Query(`SELECT id, created_at, total_amount FROM orders
WHERE user_id = $1 AND created_at < $2
ORDER BY created_at DESC
LIMIT 20`, c.Query("user_id"), lastCreated)
}
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
defer rows.Close()
orders := make([]Order, 0)
for rows.Next() {
var o Order
rows.Scan(&o.ID, &o.CreatedAt, &o.TotalAmount)
orders = append(orders, o)
}
return c.JSON(orders)
}Pastikan index mencakup user_id dan created_at agar filter dan urutan berjalan pada index. Untuk GORM, cukup tambahkan kondisi dan Order yang serupa.
Monitoring Index dan Pertumbuhan Tabel
Memantau hit rate index membantu memastikan query lama tetap berjalan optimal walau volume data naik.
Langkah Monitoring
- Gunakan
pg_stat_user_indexesuntuk melihatidx_scandanidx_tup_read. Jikaidx_scanrendah sementara query seharusnya memanfaatkan index, evaluasi kembali kondisi WHERE atau parameter binding. - Periksa tabel dengan
pg_stat_user_tablesuntuk melihatseq_scanyang tinggi. Bilaseq_scanmeningkat, mungkin index tidak dipakai karena statistik belum updated—jalankanANALYZE. - Catat pertumbuhan tabel utama (misal orders) dengan
SELECT relname, n_live_tup FROM pg_stat_user_tables;. Pertumbuhan tajam dapat memperlambat query jika index tidak sesuai.
Catatan Debugging
Jika query masih lambat setelah menambahkan index, pastikan parameter yang masuk ke Go Fiber tidak menyebabkan PostgreSQL memilih suboptimal plan. Untuk query dinamis, pertimbangkan PREPARE atau hint SET enable_seqscan = OFF hanya untuk debugging sementara. Simpan juga hasil EXPLAIN ANALYZE per release agar bisa membandingkan sebelum dan sesudah perubahan indeks.
Kesimpulan
Dengan memahami EXPLAIN ANALYZE, memilih index yang akurat, serta menerapkan keyset pagination, Go Fiber dapat tetap responsif walau tabel Postgres tumbuh. Tambahkan monitoring sederhana untuk memastikan index selalu digunakan dan jangan lupa meriview query apabila ada perubahan pola akses.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!