Ketika tabel terus tumbuh, query Laravel yang semula cepat bisa menjadi beban berat. Artikel ini langsung menjawab bagaimana Anda bisa mendiagnosa masalah tersebut dengan EXPLAIN, kemudian mempercepat query melalui indeks yang tepat dan pagination efisien, serta memverifikasi perubahan lewat pengukuran sebelum dan sesudah.
Fokusnya pada langkah-langkah praktis—berdasarkan query builder Laravel, analisis indeks, teknik pagination berkelanjutan, dan metrik sederhana—bukan sekadar teori.
Diagnosa Query Lambat dengan EXPLAIN dan Log
Langkah pertama adalah memahami perilaku query saat dijalankan. Laravel memudahkan kita mengakses string SQL yang dihasilkan:
$query = DB::table('orders')
->where('status', 'completed')
->whereBetween('created_at', [$start, $end])
->orderBy('created_at', 'desc');
$sql = Str::replaceArray('?', $query->toSql(), collect($query->getBindings())->map(fn($val) => DB::getPdo()->quote($val))->toArray());
$explain = DB::select('EXPLAIN '.$sql);
Dengan EXPLAIN Anda bisa melihat jenis scan, kolom yang digunakan untuk join, serta perkiraan jumlah baris. Fokuskan perhatian pada kolom type (hindari ALL) dan rows (semakin kecil semakin baik). Catat juga apakah possible_keys mencantumkan indeks yang relevan.
Tambahkan log waktu eksekusi via DB::enableQueryLog() atau paket seperti Laravel Telescope untuk mendapatkan baseline durasi. Bila tabel sudah berukuran besar, perhatikan apakah query time meningkat seiring bertambahnya data.
Menafsirkan Output EXPLAIN
- type: cari
rangeatauref;ALLberarti full table scan. - key dan key_len: menandakan indeks yang digunakan dan panjangnya.
- rows: estimasi baris yang dibaca; semakin kecil semakin efisien.
Kalau key kosong padahal ada indeks yang relevan, tinjau apakah kolom ada dalam kondisi WHERE/ORDER BY dalam urutan yang sama seperti indeks.
Analisis dan Optimasi Indeks
Gunakan hasil EXPLAIN sebagai panduan untuk membuat atau menyusun ulang indeks. Tabel yang terus tumbuh menjadi alasan kuat memakai indeks komposit daripada indeks tunggal berulang.
Contoh Index Komposit Optimal
Jika query Anda biasanya:
SELECT * FROM orders
WHERE user_id = ? AND status = ?
ORDER BY created_at DESC
LIMIT 50;
Indeks komposit yang efektif adalah:
ALTER TABLE orders ADD INDEX idx_user_status_createdAt (user_id, status, created_at DESC);
Urutan kolom penting: MySQL hanya akan memakai indeks jika kondisi WHERE mencakup prefiks dari indeks. Di contoh di atas, user_id harus berada di depan karena selalu digunakan pada WHERE. created_at ditempatkan terakhir untuk membantu ORDER BY.
Perhatikan trade-off: indeks menambah overhead penulisan. Prioritaskan indeks untuk query yang paling sering diakses atau paling lambat.
Tips Memeriksa Indeks
- Gunakan
SHOW INDEX FROM ordersuntuk melihat indeks yang ada dan kolom yang terlibat. - Pastikan tidak ada indeks duplikat yang membebani insert/update.
- Beberapa kolom filter jarang berubah (misalnya status). Jika banyak card pada status tertentu, tambahkan kolom lain ke indeks untuk mengurangi jumlah baris yang di-scan.
Jika query memiliki banyak OR/IN, pertimbangkan pemecahan query atau view materialized untuk menghindari indeks tidak digunakan.
Pagination Efisien untuk Tabel Besar
Pagination klasik menggunakan OFFSET membuang baris dan semakin lambat saat page tinggi. Gunakan teknik pagination berdasarkan offset terkini (cursor-based) atau where < id:
$items = DB::table('orders')
->where('user_id', $userId)
->where('created_at', '<=', $lastCreatedAt)
->orderBy('created_at', 'desc')
->limit(50)
->get();
Cara ini menjaga penggunaan indeks karena hanya mengambil baris setelah nilai terakhir. Jika menggunakan Eloquent, manfaatkan cursorPaginate() yang lebih ringan untuk tabel besar.
Hindari mengurutkan dengan fungsi kompleks atau kolom yang tidak memiliki indeks. Jika perlu sort berdasarkan kolom yang jarang dipakai, pertimbangkan kolom tambahan yang mencerminkan urutan itu.
Menguji Sebelum dan Sesudah
Setelah perubahan, pastikan optimasi memberi dampak nyata.
- Catat durasi rata-rata query sebelum optimasi (gunakan log atau profiler).
- Jalankan query utama dengan data yang sama, dan ambil EXPLAIN untuk memastikan indeks sudah dipakai.
- Ukur kembali durasi dan bandingkan row count dari
EXPLAIN.
Gunakan DB::enableQueryLog() untuk melihat query time dan bindings:
DB::enableQueryLog();
// Jalankan request/index
$logs = DB::getQueryLog();
Perhatikan query_time atau nilai duration dari profiler lain. Jika durasi tidak berkurang, periksa apakah indices digunakan dengan benar atau apakah sumber masalah sebenarnya pada join atau network.
Kesimpulan
Diagnosa query lambat di Laravel dimulai dari EXPLAIN dan log, lalu dilanjutkan dengan indeks yang sesuai dan pagination efisien. Indeks komposit yang dirancang sesuai pola query akan mencegah full table scan, sementara pagination berbasis cursor menjaga performa saat tabel tumbuh.
Selalu ukur sebelum dan sesudah perubahan agar bisa membuktikan dampaknya. Menggabungkan langkah-langkah tersebut membuat aplikasi tetap responsif meski data semakin besar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!