Home / Artikel / Web Development
Web Development

Query MySQL Lambat? Mulai dari EXPLAIN, Bukan Menambah Server

Query yang lambat sering membuat orang buru-buru menambah RAM, CPU, atau kapasitas hosting. Padahal, langkah pertama yang lebih masuk akal adalah melihat cara MySQL mengeksekusi query tersebut melalui EXPLAIN.

Query MySQL Lambat? Mulai dari EXPLAIN, Bukan Menambah Server

Ketika halaman website mulai lambat, database sering menjadi tersangka pertama. Masalahnya, banyak orang langsung menambah spesifikasi server tanpa mencari tahu query mana yang sebenarnya bermasalah. Padahal, satu query yang membaca ratusan ribu baris secara tidak perlu bisa tetap lambat meskipun server dibuat lebih mahal.

Di sinilah EXPLAIN berguna. Perintah ini membantu kita melihat rencana eksekusi query: tabel mana yang dibaca lebih dulu, indeks apa yang dipakai, berapa banyak baris yang diperkirakan diproses, dan bagaimana tabel-tabel digabungkan. MySQL juga menyediakan EXPLAIN ANALYZE untuk membandingkan perkiraan optimizer dengan kondisi saat query benar-benar berjalan. ([dev.mysql.com](https://dev.mysql.com/doc/refman/8.4/en/explain.html?utm_source=openai))

EXPLAIN itu seperti peta perjalanan query

Bayangkan Anda meminta seseorang mencari satu buku di perpustakaan besar. Ada dua cara. Ia bisa memeriksa setiap rak satu per satu, atau memakai katalog yang langsung menunjukkan lokasi buku. Dalam database, katalog itu kira-kira berperan seperti index.

Tanpa index yang sesuai, MySQL mungkin perlu membaca banyak baris untuk menemukan data yang cocok. Dengan index, database dapat mempersempit pencarian. Namun, index bukan tombol ajaib. Terlalu banyak index juga menambah pekerjaan saat data baru dimasukkan, diubah, atau dihapus. Dokumentasi MySQL sendiri menekankan bahwa index perlu dipilih dengan seimbang karena memiliki biaya penyimpanan dan biaya pemeliharaan. ([dev.mysql.com](https://dev.mysql.com/doc/refman/8.4/en/optimization-indexes.html?utm_source=openai))

Contoh sederhana yang bisa langsung dicoba

Misalnya kita memiliki tabel orders dan sering menjalankan query berikut:

SELECT id, customer_id, total_amount
FROM orders
WHERE customer_id = 42
AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

Sebelum menebak-nebak, jalankan:

EXPLAIN
SELECT id, customer_id, total_amount
FROM orders
WHERE customer_id = 42
AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

Hasilnya biasanya berbentuk tabel dengan kolom seperti type, possible_keys, key, rows, dan Extra. Anda tidak harus memahami semuanya sekaligus. Mulailah dari tiga hal berikut:

  • key: index yang benar-benar dipilih MySQL. Jika nilainya kosong, belum tentu pasti bermasalah, tetapi perlu diperiksa.
  • rows: perkiraan jumlah baris yang harus dibaca. Angka yang sangat besar patut dicurigai, terutama jika hasil akhir query hanya membutuhkan beberapa baris.
  • type: gambaran cara MySQL mengakses data. Akses berbasis index umumnya lebih efisien daripada membaca seluruh tabel, tetapi arti terbaiknya tetap bergantung pada ukuran data dan bentuk query.

Jangan hanya menambahkan index satu per satu

Kesalahan umum adalah membuat index terpisah untuk setiap kolom:

CREATE INDEX idx_customer ON orders (customer_id);
CREATE INDEX idx_status ON orders (status);
CREATE INDEX idx_created ON orders (created_at);

Index tersebut mungkin membantu sebagian query, tetapi belum tentu menjadi pilihan terbaik untuk query contoh. Karena query memakai beberapa kondisi sekaligus dan pengurutan berdasarkan tanggal, kita perlu menguji kemungkinan composite index, yaitu index yang mencakup lebih dari satu kolom.

CREATE INDEX idx_orders_customer_status_created
ON orders (customer_id, status, created_at);

Urutan kolom penting. Pada composite index, MySQL dapat memanfaatkan bagian paling kiri dari susunan index. Index (customer_id, status, created_at) dapat membantu pencarian berdasarkan customer_id, atau berdasarkan customer_id dan status. Namun, index yang sama belum tentu membantu query yang hanya mencari berdasarkan status. Konsep ini dikenal sebagai leftmost prefix. ([dev.mysql.com](https://dev.mysql.com/doc/refman/8.4/en/multiple-column-indexes.html?utm_source=openai))

Bandingkan sebelum dan sesudah

Jangan menganggap query pasti lebih cepat hanya karena sebuah index sudah dibuat. Jalankan EXPLAIN sebelum perubahan, tambahkan index di lingkungan pengujian, lalu jalankan lagi. Perhatikan apakah nilai key berubah dan apakah perkiraan rows turun.

Untuk pengujian yang lebih realistis, gunakan:

EXPLAIN ANALYZE
SELECT id, customer_id, total_amount
FROM orders
WHERE customer_id = 42
AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

Perintah ini menjalankan query dan menampilkan informasi waktu aktual, jumlah baris yang dikembalikan, serta jumlah pengulangan pada tiap bagian rencana eksekusi. Karena query benar-benar dijalankan, gunakan dengan hati-hati pada operasi yang mengubah data dan utamakan lingkungan staging atau salinan data yang aman. ([dev.mysql.com](https://dev.mysql.com/doc/refman/8.4/en/explain.html?utm_source=openai))

Jika index tidak dipakai, jangan langsung menyalahkan MySQL

Ada beberapa alasan query tidak menggunakan index yang sudah tersedia. Bisa jadi tabel terlalu kecil sehingga membaca seluruh tabel dianggap lebih murah. Bisa juga kondisi query membuat index kurang efektif, misalnya fungsi diterapkan pada kolom:

SELECT * FROM users
WHERE YEAR(created_at) = 2026;

Pada bentuk seperti ini, database mungkin kesulitan memakai index biasa pada created_at. Salah satu pendekatan yang lebih ramah index adalah menggunakan rentang tanggal:

SELECT * FROM users
WHERE created_at >= '2026-01-01'
AND created_at < '2027-01-01';

Perbandingan tipe data juga penting. Kolom yang dipakai dalam join sebaiknya memiliki tipe dan ukuran yang kompatibel. Selain itu, pola pencarian seperti LIKE '%kata%' biasanya tidak memberi peluang yang sama bagi index B-tree seperti pencarian yang memiliki awalan tetap.

Apa artinya bagi kita?

Performa database bukan sekadar urusan server besar. Yang lebih penting adalah memastikan aplikasi meminta data dengan cara yang masuk akal. Query sederhana yang dijalankan ribuan kali per menit dapat menjadi beban besar, sedangkan query yang lebih kompleks mungkin tetap baik jika memakai rencana eksekusi yang tepat.

Biasakan mencatat query yang lambat, menguji dengan data yang mendekati kondisi produksi, dan membaca EXPLAIN sebelum mengubah struktur database. Jika menggunakan framework PHP, periksa juga query yang dihasilkan oleh ORM atau query builder. Kadang masalah bukan pada satu query yang terlihat di kode, melainkan pada pola N+1 query: aplikasi mengambil daftar utama, lalu menjalankan query tambahan untuk setiap item.

Yang bisa dilakukan sekarang

  1. Pilih satu halaman yang terasa lambat dan catat query database yang dijalankan.
  2. Jalankan EXPLAIN pada query tersebut.
  3. Periksa kolom key, rows, dan Extra.
  4. Pastikan kondisi WHERE, kolom join, dan pengurutan memiliki strategi index yang sesuai.
  5. Uji perubahan di staging, lalu bandingkan waktu sebelum dan sesudah.
  6. Hapus index yang benar-benar tidak digunakan hanya setelah memeriksa dampaknya pada query lain.

Langkah ini mungkin terasa lebih lambat daripada langsung menaikkan paket hosting. Namun, hasilnya biasanya lebih tahan lama: kita tidak hanya membeli tenaga komputasi tambahan, tetapi memahami mengapa aplikasi bekerja lambat dan memperbaiki sumber masalahnya.

Sumber & bacaan lebih lanjut

– Rio Yotto @rioyotto