Ketika sebuah halaman terasa lambat, godaan pertama biasanya menyalahkan server, koneksi internet, atau database. Padahal, satu permintaan halaman bisa melewati banyak titik: browser menunggu koneksi, PHP menjalankan logika, aplikasi memanggil API, MySQL mencari data, lalu hasilnya dirender kembali ke pengguna.
Masalahnya, memperbaiki bagian yang salah hanya membuang waktu. Menambah kapasitas hosting tidak akan banyak membantu jika penyebabnya adalah query tanpa indeks. Sebaliknya, mengutak-atik SQL tidak akan menyelesaikan masalah jika waktu terbesar habis untuk memanggil API eksternal.
Pendekatan yang lebih aman adalah melacak perjalanan request dari ujung ke ujung. Anggap saja seperti mengirim paket: kita perlu tahu apakah keterlambatan terjadi saat paket berangkat, diproses di gudang, atau diantar ke tujuan.
Mulai dari pengalaman pengguna, bukan dugaan developer
Pengguna tidak peduli apakah keterlambatan terjadi di PHP atau MySQL. Mereka hanya melihat halaman yang belum muncul, tombol yang tidak segera merespons, atau proses checkout yang terasa macet.
Karena itu, ukur dulu apa yang dirasakan pengguna. Browser menyediakan informasi penting melalui panel Network di Developer Tools. Perhatikan beberapa bagian berikut:
- Request start: kapan browser mulai mengirim permintaan.
- Waiting atau TTFB: berapa lama sampai server mengirim byte pertama.
- Content download: berapa lama hasil respons diunduh.
- Ukuran respons: apakah server mengirim data jauh lebih banyak dari yang diperlukan.
Jika waktu Waiting sangat panjang, kemungkinan masalah berada di server, aplikasi, database, atau layanan eksternal. Jika server cepat tetapi halaman tetap terasa berat, periksa JavaScript, gambar, dan proses rendering di browser.
Pengukuran seperti ini lebih berguna daripada kalimat “server terasa lambat”. Performa web sebaiknya dilihat dari pengalaman nyata pengguna, bukan hanya dari waktu fungsi tertentu selesai di komputer developer.
Tambahkan penanda waktu di aplikasi PHP
Langkah berikutnya adalah memecah proses di sisi server. Jangan hanya mencatat bahwa satu halaman membutuhkan dua detik. Catat bagian mana yang menggunakan dua detik tersebut.
Contoh sederhana:
<?php
$startedAt = microtime(true);
$beforeDb = microtime(true);
$orders = getOrders($userId);
$dbTime = microtime(true) - $beforeDb;
$beforeApi = microtime(true);
$shipping = getShippingStatus($orders);
$apiTime = microtime(true) - $beforeApi;
$totalTime = microtime(true) - $startedAt;
error_log(json_encode([
'request' => $_SERVER['REQUEST_URI'] ?? '',
'db_ms' => round($dbTime * 1000, 2),
'api_ms' => round($apiTime * 1000, 2),
'total_ms' => round($totalTime * 1000, 2)
]));
?>Fungsi error_log() dapat mengirim pesan ke log sistem atau file yang dikonfigurasi. Untuk produksi, logging sebaiknya tidak menampilkan data sensitif seperti password, token, atau isi lengkap alamat pelanggan.
Log juga perlu memiliki informasi yang membantu pencarian, misalnya URL, metode HTTP, ID permintaan, dan waktu proses. Jangan mencatat semua hal secara membabi buta karena log yang terlalu ramai justru menyulitkan investigasi dan dapat memenuhi penyimpanan server.
Periksa apakah aplikasi melakukan terlalu banyak pekerjaan
Banyak aplikasi lambat bukan karena satu operasi yang sangat buruk, melainkan karena terlalu banyak operasi kecil. Contohnya, halaman daftar pesanan mengambil 50 pesanan, lalu menjalankan query pelanggan satu per satu untuk setiap baris.
Pola ini sering disebut N+1 query. Secara visual, kode terlihat sederhana, tetapi jumlah query dapat meningkat seiring jumlah data.
// Berpotensi menghasilkan banyak query
foreach ($orders as $order) {
$customer = findCustomer($order['customer_id']);
renderOrder($order, $customer);
}Solusinya bisa berupa satu query dengan JOIN, mengambil data pelanggan dalam satu batch, atau menggunakan mekanisme eager loading jika framework yang dipakai mendukungnya.
Namun, jangan langsung mengubah kode berdasarkan dugaan. Catat jumlah query dan waktunya terlebih dahulu. Perbaikan yang baik adalah perbaikan yang bisa dibandingkan sebelum dan sesudah.
Gunakan EXPLAIN sebelum menambah indeks
Indeks database memang dapat mempercepat pencarian, tetapi menambahkan indeks secara acak bukan strategi yang baik. Indeks juga membutuhkan ruang dan dapat menambah pekerjaan ketika data ditulis atau diperbarui.
Gunakan EXPLAIN untuk melihat bagaimana MySQL merencanakan eksekusi sebuah query.
EXPLAIN
SELECT id, customer_id, status, created_at
FROM orders
WHERE customer_id = 42
AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;Perhatikan apakah MySQL memakai indeks yang relevan, berapa banyak baris yang diperkirakan dibaca, dan apakah proses pengurutan dilakukan secara mahal. Pada MySQL yang mendukungnya, EXPLAIN ANALYZE dapat membantu membandingkan perkiraan optimizer dengan waktu dan jumlah baris yang benar-benar terjadi.
Indeks gabungan mungkin lebih sesuai daripada dua indeks terpisah, tetapi urutannya tetap harus mengikuti pola filter dan pengurutan yang sering digunakan. Ini bukan aturan yang bisa diterapkan tanpa melihat query nyata dan distribusi data.
Jangan lupakan API dan layanan eksternal
Jika aplikasi memanggil API pembayaran, pengiriman, email, atau layanan AI dalam alur request utama, keterlambatan layanan tersebut ikut dirasakan pengguna. Bahkan jika server dan database Anda cepat, satu API yang lambat dapat membuat halaman menunggu.
Catat durasi setiap panggilan eksternal, status respons, dan jumlah percobaan ulang. Beri batas waktu timeout yang masuk akal. Tanpa timeout, satu layanan yang tidak merespons dapat membuat worker PHP tertahan terlalu lama.
Untuk proses yang tidak harus selesai sebelum halaman tampil, pertimbangkan pola asynchronous. Misalnya, setelah pesanan tersimpan, pengiriman email konfirmasi dapat dimasukkan ke antrean untuk diproses di belakang layar. Pengguna tidak perlu menunggu proses yang tidak berhubungan langsung dengan tampilan halaman.
Apa artinya bagi kita?
Performa bukan perlombaan menghapus milidetik dari satu fungsi. Yang lebih penting adalah menemukan bagian yang paling banyak memengaruhi pengalaman pengguna dan risiko bisnis.
Mulailah dengan alur yang penting: login, pencarian, checkout, dashboard, atau endpoint API yang paling sering dipakai. Ukur total waktu, pecah menjadi beberapa tahap, lalu perbaiki bottleneck terbesar. Setelah itu, ukur ulang dengan data yang sebanding.
Checklist yang bisa dilakukan sekarang
- Buka panel Network dan cek apakah keterlambatan terjadi sebelum atau sesudah server mengirim respons.
- Tambahkan pencatatan waktu di batas penting: sebelum query, sesudah query, sebelum API, dan sebelum respons dikirim.
- Hitung jumlah query dalam satu request dan cari pola N+1.
- Jalankan
EXPLAINpada query yang lambat sebelum mengubah indeks. - Tambahkan timeout dan logging untuk setiap layanan eksternal.
- Bandingkan hasil sebelum dan sesudah perbaikan menggunakan data yang sama.
Dengan cara ini, debugging performa berubah dari tebak-tebakan menjadi proses investigasi. Anda tidak perlu langsung mengganti hosting atau menulis ulang aplikasi. Sering kali, satu pengukuran yang tepat sudah cukup untuk menunjukkan bagian mana yang sebenarnya perlu diperbaiki.
Sumber & bacaan lebih lanjut
- MySQL 8.0 Reference Manual: EXPLAIN Statement
- PHP Manual: error_log
- PHP Manual: Runtime Configuration for Error Handling
- web.dev: User-centric performance metrics
– Rio Yotto @rioyotto
