0Pricing
MongoDB Academy · บทเรียน

การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา

ผู้เรียนจะตีความขั้นตอน IXSCAN เทียบกับ COLLSCAN ในผลลัพธ์ของ explain และระบุดัชนีที่ขาดหายจากอัตราส่วนระหว่าง nReturned กับ docsExamined

การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา เป็นบทเรียน MongoDB Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน MongoDB Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

Why explain() Matters

Slow queries in MongoDB are usually caused by missing indexes or suboptimal query plans. The explain() method reveals exactly what MongoDB did to execute a query: which index it chose, how many documents it scanned, and how long each stage took. Without explain(), performance tuning is guesswork; with it, you get a precise diagnostic report.

// Three verbosity levels
db.users.find({ age: { $gt: 25 } }).explain();              // 'queryPlanner'
db.users.find({ age: { $gt: 25 } }).explain('executionStats'); // includes timing
db.users.find({ age: { $gt: 25 } }).explain('allPlansExecution'); // all candidate plans

queryPlanner Mode

The default explain() mode returns the query planner output: the winning plan and rejected plans, but without actually executing the query. This is fast and useful for a quick look at the plan structure. The key field is winningPlan, which describes the execution stage tree MongoDB would use.

const result = db.orders.find({ userId: 'u1' }).explain();

// winningPlan shows the chosen execution strategy
console.log(JSON.stringify(result.queryPlanner.winningPlan, null, 2));
// Example:
// { 'stage': 'FETCH',
//   'inputStage': {
//     'stage': 'IXSCAN',
//     'indexName': 'userId_1' } }

IXSCAN vs COLLSCAN

The two most important stage names in explain() output are: IXSCAN (Index Scan) — the query used an index; and COLLSCAN (Collection Scan) — MongoDB scanned every document. A COLLSCAN on a production collection with millions of documents is almost always a bug. Seeing COLLSCAN is the first sign that you need to add or refine an index.

// BAD: COLLSCAN means no usable index
// { 'stage': 'COLLSCAN', 'filter': { 'email': { '$eq': 'a@b.com' } } }

// GOOD: IXSCAN means an index was used
// { 'stage': 'IXSCAN', 'indexName': 'email_1', 'direction': 'forward' }

// Fix: create the missing index
db.users.createIndex({ email: 1 });

executionStats Mode

explain('executionStats') actually runs the query and collects timing data. The most important metrics are: nReturned — documents returned to the client; totalDocsExamined — documents MongoDB inspected; and totalKeysExamined — index entries scanned. An efficient query should have nReturned ≈ totalDocsExamined. A large gap signals wasted work.

const stats = db.orders
  .find({ userId: 'u1', status: 'active' })
  .explain('executionStats');

const s = stats.executionStats;
console.log('Returned:       ', s.nReturned);
console.log('Keys Examined:  ', s.totalKeysExamined);
console.log('Docs Examined:  ', s.totalDocsExamined);
console.log('Execution ms:   ', s.executionTimeMillis);

Interpreting Key Ratios

Three ratios tell you how efficient a query is: keys examined / keys returned (low is good, 1:1 is perfect), docs examined / docs returned (should be close to 1), and docs examined / keys examined (much greater than 1 means the index is filtering well but fetch is expensive). These ratios guide whether you need a better index, a covered query, or a different filter strategy.

// Efficiency check formula
const ratio = s.totalDocsExamined / s.nReturned;
// ratio = 1  -> perfect, index is very selective
// ratio = 10 -> for every doc returned, 10 were scanned (room to improve)
// ratio = 1000+ -> strong signal to add or redesign index

The FETCH Stage

After an IXSCAN identifies matching index entries, MongoDB may need to FETCH the actual documents from disk to check conditions not covered by the index, or to return fields not in the index. A covered query eliminates the FETCH stage entirely. If you see IXSCAN → FETCH with a high totalDocsExamined, consider adding projected fields to the index to enable coverage.

// With IXSCAN only on userId, fetching to check 'status' adds FETCH
// winningPlan:
// { stage: 'FETCH',
//   filter: { status: { $eq: 'active' } },
//   inputStage: { stage: 'IXSCAN', indexName: 'userId_1' } }

// Fix: compound index so status is in the index too
db.orders.createIndex({ userId: 1, status: 1 });
// Now: IXSCAN only, no FETCH needed for the filter

Rejected Plans and the Plan Cache

MongoDB evaluates multiple candidate plans in parallel during a trial run and picks the winner based on how many documents each plan returns per unit of work. The winning plan is cached for that query shape so future executions skip re-evaluation. You can view rejected plans using allPlansExecution verbosity. The cache is invalidated when indexes change or collection statistics update significantly.

// See all candidate plans and why the winner was chosen
const allPlans = db.orders
  .find({ userId: 'u1', status: 'active' })
  .explain('allPlansExecution');

// rejectedPlans shows what MongoDB tried but discarded
console.log(allPlans.queryPlanner.rejectedPlans.length, 'plans rejected');

SORT and SORT_KEY Stages

When MongoDB cannot use an index to satisfy a sort, it adds an in-memory SORT stage to the plan. In-memory sorts are limited to 100 MB by default; beyond that, the query fails unless you enable allowDiskUse. Seeing a SORT stage is a signal to add a compound index whose key order matches the sort, eliminating the in-memory sort entirely.

// explain shows in-memory sort when index doesn't cover the sort order
// { stage: 'SORT', sortPattern: { createdAt: -1 },
//   inputStage: { stage: 'IXSCAN', ... } }

// Fix: compound index that includes the sort field
db.orders.createIndex({ userId: 1, createdAt: -1 });
// Now the SORT stage disappears from the plan

Forcing an Index With hint()

MongoDB's query planner usually chooses the best index, but sometimes it picks a suboptimal plan (especially when statistics are stale). You can force a specific index with .hint(), passing either the index key pattern or the index name. This is useful for debugging to compare plans or as a last resort in production when the planner makes poor choices.

// Force use of a specific index by key pattern
db.orders.find({ userId: 'u1', status: 'active' })
  .hint({ userId: 1, status: 1 })
  .explain('executionStats');

// Force by index name
db.orders.find({ userId: 'u1' })
  .hint('idx_orders_user');

// Force a COLLSCAN (bypass all indexes)
db.orders.find({ userId: 'u1' })
  .hint({ $natural: 1 });

explain() on Aggregation Pipelines

Aggregation pipelines also support explain(). Pass { explain: true } to aggregate() to see how the pipeline stages execute and whether early stages like $match use indexes. The key insight: a $match at the start of the pipeline can push a filter down to an IXSCAN; a $match after a $group cannot.

// explain() on an aggregation pipeline
db.orders.explain('executionStats').aggregate([
  { $match: { userId: 'u1', status: 'active' } }, // <-- pushed to IXSCAN
  { $group: { _id: '$productId', total: { $sum: '$amount' } } },
  { $sort: { total: -1 } }
]);

Common explain() Red Flags

When reviewing explain() output, watch for these warning signs: a COLLSCAN on a large collection; totalDocsExamined much greater than nReturned; an in-memory SORT stage; or executionTimeMillis above your SLA. Each of these indicates a specific remediation: add an index, change the index key order, add sort fields to the compound index, or redesign the query.

// Red flag checklist:
// 1. stage: 'COLLSCAN' -> add index
// 2. totalDocsExamined >> nReturned -> compound index or partial index
// 3. stage: 'SORT' -> extend compound index to cover sort order
// 4. executionTimeMillis > 100 -> investigate stages above

Quick Check

Test your understanding of MongoDB explain() output from this lesson.

Lesson Recap

In this lesson you learned: explain('executionStats') runs the query and provides timing and document counts, COLLSCAN vs IXSCAN in the winning plan instantly tells you whether an index was used, and the nReturned / totalDocsExamined ratio measures index efficiency. Next up we explore text indexes for full-text search.

คำถามที่พบบ่อย

บทเรียน “การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส MongoDB Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา”

ผู้เรียนจะตีความขั้นตอน IXSCAN เทียบกับ COLLSCAN ในผลลัพธ์ของ explain และระบุดัชนีที่ขาดหายจากอัตราส่วนระหว่าง nReturned กับ docsExamined คุณปฏิบัติ MongoDB Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน MongoDB Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน MongoDB Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน MongoDB Academy นี้ได้ไหม

ได้ บทเรียน MongoDB Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทำงานของดัชนี B-Tree ใน MongoDB
  2. การสร้างดัชนีฟิลด์เดียวและดัชนีผสม
  3. คุณสมบัติดัชนี: ไม่ซ้ำ กระจายบางส่วน บางส่วน และ TTL
  4. การอ่านผลลัพธ์จาก explain() เพื่อวินิจฉัยการค้นหา
← กลับไปที่ MongoDB Academy