Ketika sebuah website mulai lambat, perhatian biasanya langsung tertuju pada ukuran server, koneksi internet, atau framework yang digunakan. Padahal, salah satu penyebab yang sering luput adalah cara database mencari data. MySQL bisa bekerja sangat cepat, tetapi tanpa index yang tepat, pencarian sederhana dapat berubah menjadi pemeriksaan ribuan atau jutaan baris.
Index adalah struktur tambahan yang membantu database menemukan data tanpa membaca seluruh isi tabel. Ibarat mencari nama di buku telepon, kita tidak perlu membuka setiap halaman dari awal jika daftar nama sudah diurutkan. Namun, index bukan solusi yang bisa dipasang sebanyak-banyaknya. Index juga memakai ruang penyimpanan dan membuat proses tambah, ubah, atau hapus data sedikit lebih berat.
Apa yang sebenarnya dilakukan index?
Bayangkan sebuah tabel orders berisi jutaan pesanan. Jika aplikasi menjalankan query berikut:
SELECT * FROM orders WHERE user_id = 125;Tanpa index pada kolom user_id, database mungkin harus memeriksa baris satu per satu untuk menemukan pesanan milik pengguna tersebut. Proses ini disebut pemindaian tabel atau full table scan.
Jika tersedia index pada user_id, MySQL dapat menggunakan struktur index untuk langsung mempersempit lokasi data yang relevan. Hasilnya, jumlah baris yang perlu diperiksa bisa jauh lebih sedikit.
CREATE INDEX idx_orders_user_id ON orders (user_id);Perlu dicatat, index tidak membuat semua query otomatis cepat. Database tetap harus memilih apakah index tersebut layak digunakan berdasarkan kondisi query dan distribusi data.
Kolom apa yang biasanya perlu di-index?
Kolom yang sering digunakan dalam beberapa pola query berikut biasanya menjadi kandidat index:
- WHERE, untuk menyaring data berdasarkan nilai tertentu.
- JOIN, untuk menghubungkan data dari dua tabel.
- ORDER BY, ketika aplikasi sering mengurutkan data berdasarkan kolom tertentu.
- GROUP BY, dalam kondisi tertentu ketika pengelompokan dilakukan berulang.
- UNIQUE, seperti alamat email atau kode transaksi yang tidak boleh sama.
Primary key secara umum sudah memiliki index. Karena itu, menambahkan index kedua pada kolom primary key biasanya tidak memberikan manfaat.
Contoh yang umum adalah halaman daftar pesanan milik pengguna:
SELECT id, total, status, created_at
FROM orders
WHERE user_id = 125
ORDER BY created_at DESC
LIMIT 20;Query tersebut tidak hanya menyaring berdasarkan user_id, tetapi juga mengurutkan berdasarkan created_at. Index gabungan dapat lebih sesuai:
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at);Urutan kolom dalam index gabungan itu penting
Index gabungan adalah index yang terdiri dari beberapa kolom. Urutan kolomnya tidak boleh dipilih secara acak. Pada contoh tadi, user_id ditempatkan lebih dulu karena digunakan untuk menyaring data, kemudian created_at digunakan untuk membantu pengurutan.
Secara sederhana, index dengan susunan (user_id, created_at) cocok untuk query yang mencari berdasarkan user_id. Namun, index itu belum tentu efektif untuk query yang hanya mencari berdasarkan created_at.
Contoh berikut memiliki kebutuhan berbeda:
SELECT * FROM orders
WHERE status = 'pending'
AND created_at > '2026-09-01';Index yang mungkin relevan adalah (status, created_at), terutama jika aplikasi sering menampilkan pesanan berdasarkan status dan rentang waktu. Meski demikian, pilihan terbaik tetap bergantung pada jumlah data dan pola query nyata.
Gunakan EXPLAIN sebelum menebak
Daripada langsung menambah index, gunakan EXPLAIN untuk melihat bagaimana MySQL menjalankan query.
EXPLAIN SELECT id, total, status, created_at
FROM orders
WHERE user_id = 125
ORDER BY created_at DESC
LIMIT 20;Hasil EXPLAIN dapat membantu melihat beberapa hal penting:
- type: gambaran cara akses data yang digunakan.
- possible_keys: index yang mungkin dipertimbangkan.
- key: index yang benar-benar dipilih.
- rows: perkiraan jumlah baris yang perlu diperiksa.
- Extra: informasi tambahan, termasuk kemungkinan operasi pengurutan atau pemindaian.
Jika query hanya mengembalikan 20 baris tetapi MySQL memperkirakan harus memeriksa ratusan ribu baris, itu tanda bahwa query atau index perlu diperiksa lebih lanjut. Angka pada EXPLAIN adalah perkiraan, bukan selalu jumlah aktual, tetapi tetap berguna untuk menemukan masalah besar.
Kesalahan umum saat menambahkan index
Memberi index pada semua kolom
Menambahkan index ke setiap kolom terlihat aman, tetapi justru dapat memperbesar ukuran database dan memperlambat operasi tulis. Setiap kali baris ditambahkan atau diubah, index terkait juga perlu diperbarui.
Mengabaikan kolom dengan variasi nilai rendah
Kolom seperti is_active yang hanya berisi 0 dan 1 sering tidak terlalu selektif jika berdiri sendiri. Index pada kolom semacam ini belum tentu bermanfaat, terutama jika sebagian besar data memiliki nilai yang sama.
Mengubah kolom di dalam kondisi WHERE
Perhatikan query seperti berikut:
SELECT * FROM users
WHERE LOWER(email) = 'user@example.com';Penggunaan fungsi pada kolom dapat membuat index biasa sulit dimanfaatkan, tergantung versi dan konfigurasi database. Untuk kasus seperti pencarian email, lebih baik menormalisasi nilai saat disimpan atau merancang strategi index yang sesuai.
Mengabaikan query yang sebenarnya dijalankan aplikasi
Index sebaiknya dibuat berdasarkan pola akses nyata, bukan hanya struktur tabel. Query yang terlihat sederhana di kode PHP dapat menghasilkan kondisi berbeda setelah ditambah filter, pengurutan, atau relasi tabel.
Langkah praktis yang bisa dilakukan sekarang
- Catat query yang terasa lambat, terutama query pada halaman daftar, pencarian, dan laporan.
- Jalankan
EXPLAINpada query tersebut. - Periksa apakah database melakukan full table scan atau membaca terlalu banyak baris.
- Bandingkan kolom pada
WHERE,JOIN, danORDER BY. - Buat index kecil yang menjawab kebutuhan query, bukan index sebanyak mungkin.
- Uji kembali dengan data yang mendekati kondisi produksi.
- Hapus index yang tidak pernah digunakan setelah melakukan pengamatan yang cukup.
Apa artinya bagi kita?
Index bukan sekadar trik optimasi yang ditambahkan ketika website sudah lambat. Ia bagian dari desain aplikasi. Saat membuat fitur baru, pertimbangkan bagaimana data akan dicari, diurutkan, dan dihubungkan.
Namun, index juga bukan pengganti query yang buruk. Meminta aplikasi mengambil semua kolom dengan SELECT *, memuat ribuan data sekaligus, atau menjalankan query berulang kali di dalam perulangan tetap dapat menjadi masalah. Performa yang sehat biasanya lahir dari kombinasi query yang masuk akal, struktur data yang rapi, index yang terukur, dan pengujian menggunakan data realistis.
Mulailah dari satu query yang benar-benar lambat. Baca rencana eksekusinya, buat perubahan kecil, lalu ukur hasilnya. Dengan pendekatan tersebut, optimasi database menjadi proses yang dapat dijelaskan—bukan sekadar menebak-nebak.
– Rio Yotto @rioyotto
