Menganalisis execution plan dengan explain(), membedakan COLLSCAN dari IXSCAN, membaca winning plan dan rejected plans, memahami metrik totalKeysExamined dan totalDocsExamined, serta mengaktifkan database profiler untuk menemukan slow queries di produksi.

Di episode 12 kalian memahami index secara teori. Tapi di dunia nyata, "aku pikir query ini pakai index" tidak pernah cukup — kalian butuh bukti. Bagaimana cara mengetahui query mana yang lambat, kenapa lambat, dan apakah index baru benar-benar berfungsi? Jawabannya ada di explain() dan database profiler.
Episode 13 mengajarkan kalian menjadi detektif performa. Roadmap-nya: pertama kita baca execution plan dengan explain("executionStats"), kedua kita bedah perbedaan COLLSCAN dan IXSCAN, ketiga kita pahami winning plan versus rejected plans, keempat kita ukur efisiensi dengan metrik kunci, dan kelima kita temukan slow queries di produksi memakai profiler. Mari mulai.
explain() menunjukkan bagaimana MongoDB mengeksekusi sebuah query — plan apa yang dipilih dan berapa banyak kerja yang dilakukan. Tambahkan opsi "executionStats" untuk melihat statistik eksekusi nyata:
db.users.find({ email: "siti@example.com" }).explain("executionStats")Hasilnya berupa dokumen besar berisi detail plan. Bagian paling penting ada di executionStats. Mari bedah field kunci yang wajib kalian kenal:
nReturned — berapa dokumen yang dikembalikan.totalKeysExamined — berapa entri index yang diperiksa.totalDocsExamined — berapa dokumen yang benar-benar dibuka dari collection.executionTimeMillis — total waktu eksekusi dalam milidetik.Aturan emas interpretasi: totalDocsExamined harus mendekati nReturned. Jika MongoDB membuka 100.000 dokumen hanya untuk mengembalikan 10, berarti ia memindai dokumen yang tidak perlu — pertanda index kurang tepat.
Di dalam plan, kalian akan menemukan stage utama yang menceritakan seluruh cerita:
IXSCAN — index scan. MongoDB memakai index untuk menemukan dokumen. Ini yang kita inginkan.COLLSCAN — collection scan. MongoDB membaca seluruh dokumen satu per satu. Ini musuh utama.executionStats: {
nReturned: 10,
totalKeysExamined: 10,
totalDocsExamined: 10,
executionTimeMillis: 2,
executionStages: {
stage: "FETCH",
inputStage: { stage: "IXSCAN", indexName: "email_1" }
}
}Pada contoh sehat di atas: totalKeysExamined: 10 sama dengan nReturned: 10, totalDocsExamined: 10, dan stage-nya IXSCAN pada index email_1. Query ini optimal — setiap dokumen yang diperiksa memang dikembalikan.
Sebaliknya, jika kalian melihat COLLSCAN dan totalDocsExamined jauh melebihi nReturned, query inilah tersangka slow query.
MongoDB tidak hanya memakai satu index per query. Untuk query dengan beberapa index potensial, optimizer menjalankan beberapa kandidat plan secara paralel, mengukur biayanya, lalu memilih yang terbaik:
winningPlan — plan yang menang dan dipakai untuk mengeksekusi query.rejectedPlans — plan yang kalah dalam kompetisi optimizer.db.orders.find(
{ userId: ObjectId("66aaaaaaaaaaaaaaaaaaaaaaaa"), status: "paid" }
).explain("allPlansExecution")Menggunakan opsi "allPlansExecution" menampilkan statistik semua plan yang diuji. Bagian ini sangat berguna saat menguji index baru: kalian bisa melihat apakah index yang kalian buat menjadi winningPlan atau masih dikalahkan index lain. Jika index baru kalian selalu muncul di rejectedPlans, berarti ia tidak memberikan keuntungan — atau urutan field compound index-nya kurang tepat (ingat aturan ESR di episode 12).
Query paling mahal adalah yang tidak bisa memakai index sama sekali. Ciri-cirinya:
$where dan $regex tanpa anchor di awal pola.$ne, $nin, $not pada field yang seharusnya dipakai index.Uji efektivitas index dengan menambahkannya lalu membandingkan executionStats sebelum dan sesudah:
db.orders.createIndex({ userId: 1, status: 1 })
db.orders.find(
{ userId: ObjectId("66aaaaaaaaaaaaaaaaaaaaaaaa"), status: "paid" }
).explain("executionStats")Jalankan explain sebelum dan sesudah membuat index. Sebelumnya kalian mungkin melihat COLLSCAN; sesudahnya IXSCAN dengan totalDocsExamined yang menurun drastis. Inilah cara membuktikan nilai sebuah index dengan data, bukan perasaan.
Query yang lambat jarang datang membawa tanda. Untuk menemukannya secara sistematis, aktifkan database profiler yang mencatat operasi melebihi ambang waktu tertentu:
db.setProfilingLevel(1, { slowms: 100 })Level 1 berarti aktif dan mencatat operasi yang melebihi slowms. Level 0 mematikan, dan level 2 mencatat semua operasi (hanya untuk debugging sesaat, karena berat).
Semua operasi yang terekam disimpan di collection system.profile dalam database yang sama. Kalian bisa query collection ini seperti biasa:
db.system.profile.find({ millis: { $gt: 100 } })
.sort({ ts: -1 })
.limit(10)Setiap dokumen berisi query asli, waktu eksekusi, dan planSummary yang menunjukkan apakah memakai index. Dari sinilah kalian mendapatkan bukti tak terbantahkan: query mana yang memakan waktu, seberapa sering, dan index apa yang dipakainya. Kemudian optimasi dengan index baru atau penulisan ulang query, dan verifikasi dengan explain.
Warning
Profiler level 2 (mencatat semua operasi) menambah beban signifikan karena setiap query ditulis ke system.profile. Jangan mengaktifkannya di produksi secara permanen — gunakan level 1 dengan slowms yang masuk akal (100ms adalah titik awal umum), lalu matikan atau naikkan ambangnya setelah investigasi selesai.
Info
Gabungkan temuan profiler dengan db.currentOp() untuk melihat operasi yang sedang berjalan saat ini — termasuk yang sudah berjalan lama dan perlu di-kill. Untuk operasi macet, jalankan db.currentOp() lalu hentikan dengan db.killOp(<opid>). Ini adalah skill penyelamat saat produksi tersendat karena satu query raksasa.
Pada episode 13 ini kalian telah menjadi detektif performa: membaca execution plan dengan explain("executionStats"), membedakan COLLSCAN yang buruk dari IXSCAN yang baik, memahami winningPlan versus rejectedPlans dalam kompetisi optimizer, mengukur efisiensi lewat metrik totalKeysExamined dan totalDocsExamined, serta mengaktifkan database profiler untuk menemukan slow queries di produksi lewat system.profile.
Inti yang harus dibawa pulang:
totalDocsExamined harus mendekati nReturned; jika tidak, ada index yang kurang tepat.COLLSCAN = musuh; IXSCAN = yang kita inginkan.rejectedPlans menunjukkan index yang kalah — gunakan untuk memvalidasi desain index.slowms menemukan query lambat di produksi.explain sebelum dan sesudah.Di episode 14 berikutnya kita masuk ke salah satu fitur paling dinanti: Multi-Document ACID Transactions. Kalian akan memahami kapan transaksi diperlukan, menulis transaksi yang mengubah beberapa dokumen lintas collection secara atomik — misalnya transfer saldo antar akun — serta mempelajari batasan dan best practices-nya. Sampai jumpa di episode 14!