กฎคำนำหน้าดัชนีผสมและหลักการ ESR
ผู้เรียนจะใช้หลักการออกแบบดัชนี Equality-Sort-Range กับดัชนีผสม เพื่อให้ครอบคลุมการค้นหาได้สูงสุด
กฎคำนำหน้าดัชนีผสมและหลักการ ESR เป็นบทเรียน MongoDB Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน MongoDB Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
Why Compound Index Field Order Matters
A compound index on multiple fields can serve a wide range of queries — but only if the fields appear in the right order. MongoDB can use a compound index to satisfy a query only if the query's filter matches a prefix of the index. The ordering of fields in the index definition directly controls which queries benefit from it.
The Prefix Rule Explained
A compound index { a: 1, b: 1, c: 1 } can be used by queries that filter on: { a }, { a, b }, or { a, b, c }. These are the prefixes. A query filtering only on { b } or { b, c } cannot use this index — it would do a collection scan. The index is like a phone book sorted by last name, then first name: you can look up by last name alone or by last + first, but not by first name alone.
// Index: { status: 1, customerId: 1, createdAt: 1 }
db.orders.createIndex({ status: 1, customerId: 1, createdAt: 1 })
// Uses index (prefix: status)
db.orders.find({ status: 'pending' })
// Uses index (prefix: status + customerId)
db.orders.find({ status: 'pending', customerId: 'c001' })
// Does NOT use index (no leading prefix)
db.orders.find({ customerId: 'c001' })The ESR Principle: Equality, Sort, Range
The ESR principle is a field-ordering rule for compound indexes: put Equality fields first, Sort fields second, and Range fields last. This ordering maximises the portion of the query the index can satisfy and minimises the number of index entries that must be examined. ESR is the most important compound index design rule in MongoDB.
// Query: find pending orders for customer c001, sorted by date,
// for dates after Jan 2025
// E: status = 'pending' (equality)
// S: createdAt (sort)
// R: customerId in ['c001','c002'] (range / $in)
// ESR-ordered index
db.orders.createIndex({ status: 1, createdAt: 1, customerId: 1 })Why Equality Fields Come First
Equality predicates (field: value or $eq) narrow the index scan to a single, fixed value. Placing them first dramatically reduces the number of index entries the query planner needs to consider. Once equality has pinpointed the exact bucket of matching keys, the sort and range operations work on a much smaller dataset.
// E first: status equality narrows to ~5% of index
// Then sort on createdAt within that slice
// Then range on amount within that sorted slice
db.orders.createIndex({ status: 1, createdAt: 1, amount: 1 })
db.orders.find({ status: 'shipped' })
.sort({ createdAt: -1 })
.hint({ status: 1, createdAt: 1, amount: 1 })Why Sort Fields Come Before Range
Placing sort fields before range fields allows MongoDB to use the index to satisfy the sort without a blocking in-memory sort. If range fields come before sort fields, MongoDB must scan all matching range documents, sort them in memory, then return results — adding CPU and memory overhead. With sort fields second, results emerge from the index already in the correct order.
// Without ESR: range before sort forces in-memory sort
db.orders.createIndex({ status: 1, amount: 1, createdAt: 1 })
db.orders.find({ status: 'pending', amount: { $gt: 50 } })
.sort({ createdAt: 1 })
// explain() shows: SORT stage (in-memory sort needed)
// With ESR: sort before range avoids in-memory sort
db.orders.createIndex({ status: 1, createdAt: 1, amount: 1 })
// explain() shows: no SORT stageRange Fields Last: Why It Works
Range predicates like $gt, $lt, $gte, $lte, $in, and regex span a contiguous portion of the index. By placing them last, MongoDB first narrows results with equality and delivers them in sort order, then applies the range check as a final filter. The index scan stays efficient because range does not break the sorted traversal order set by the sort fields.
// ESR applied correctly
// E: userId (equality)
// S: timestamp (sort)
// R: score (range)
db.events.createIndex({ userId: 1, timestamp: 1, score: 1 })
db.events.find({
userId: 'u123',
score: { $gte: 80 }
}).sort({ timestamp: -1 })Handling $in: Range or Equality?
$in with a small list of values behaves more like equality and can be placed first. When the list is large, it acts more like a range and should go later in the index. A useful rule: if the $in list has fewer than 10–20 values and you query it frequently, treat it as equality (first). For large, dynamic lists, treat it as range (last).
// Small $in (2 values) — treat as equality, put first
db.orders.createIndex({ status: 1, createdAt: 1 })
db.orders.find({ status: { $in: ['pending', 'processing'] } })
.sort({ createdAt: -1 })
// Large $in — treat as range, put last
db.orders.createIndex({ region: 1, createdAt: 1, userId: 1 })
db.orders.find({
region: 'EU',
userId: { $in: hundredsOfUserIds }
}).sort({ createdAt: -1 })Verifying ESR With explain()
Always verify your index design with explain('executionStats'). Look for: IXSCAN (index scan) — good. COLLSCAN (collection scan) — missing index. SORT stage present — in-memory sort, index field order might be wrong. keysExamined / nReturned should be close to 1 for an optimal compound index.
db.orders.find({ status: 'pending', amount: { $gt: 50 } })
.sort({ createdAt: 1 })
.explain('executionStats')
// Good: { stage: 'IXSCAN', nReturned: 42, keysExamined: 44 }
// Bad: { stage: 'COLLSCAN', nReturned: 42, docsExamined: 500000 }The Prefix Rule and Partial Index Reuse
Thanks to the prefix rule, a single well-designed compound index can replace several single-field indexes. An index on { a: 1, b: 1, c: 1 } makes separate indexes on { a: 1 } and { a: 1, b: 1 } redundant. Fewer indexes means less write overhead and less memory pressure — important for write-heavy workloads where index maintenance adds latency to every insert, update, and delete.
// One compound index replaces three single-field indexes
db.users.createIndex({ country: 1, city: 1, age: 1 })
// Redundant (covered by compound prefix rule):
// db.users.createIndex({ country: 1 }) -- REDUNDANT
// db.users.createIndex({ country: 1, city: 1 }) -- REDUNDANTIndex Selectivity and Field Order
Beyond ESR, consider selectivity — how many documents share the same value. Put the most selective equality field first (fewest duplicates). For example, userId is more selective than status. Placing the more selective field first narrows the scan faster. When multiple equality fields exist, order them most-selective to least-selective for maximum performance.
// userId is highly selective (millions of users)
// status is low-selectivity (only 5 values)
// More efficient: selective equality field first
db.orders.createIndex({ userId: 1, status: 1, createdAt: 1 })
// Less efficient: low-selectivity field first
db.orders.createIndex({ status: 1, userId: 1, createdAt: 1 })Putting ESR Into Practice
When designing a compound index, start by listing your top query's filter conditions and sort, then classify each field as E (equality), S (sort), or R (range). Build the index in that order. Run explain('executionStats') to confirm you see an IXSCAN with no SORT stage and a keysExamined/nReturned ratio near 1. Revisit the index whenever query patterns change.
// Practical checklist:
// Query: find users in 'NY' (E), sorted by signup (S), age > 18 (R)
// E: state = 'NY'
// S: signupDate
// R: age > 18
db.users.createIndex({ state: 1, signupDate: 1, age: 1 })
// Verify no in-memory sort and good key ratio:
db.users.find({ state: 'NY', age: { $gt: 18 } })
.sort({ signupDate: -1 })
.explain('executionStats')Quick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: a compound index can only be used when the query matches a prefix of the index fields, the ESR principle dictates ordering fields as Equality, Sort, Range for maximum query coverage, and placing sort fields before range fields eliminates costly in-memory sort stages. Next up we compare index intersection versus compound indexes.
เรียนรู้ JavaScript ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “กฎคำนำหน้าดัชนีผสมและหลักการ ESR” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กฎคำนำหน้าดัชนีผสมและหลักการ ESR” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส MongoDB Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กฎคำนำหน้าดัชนีผสมและหลักการ ESR”
ผู้เรียนจะใช้หลักการออกแบบดัชนี Equality-Sort-Range กับดัชนีผสม เพื่อให้ครอบคลุมการค้นหาได้สูงสุด คุณปฏิบัติ MongoDB Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน MongoDB Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน MongoDB Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “กฎคำนำหน้าดัชนีผสมและหลักการ ESR” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน MongoDB Academy นี้ได้ไหม
ได้ บทเรียน MongoDB Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ตัวสร้างโปรไฟล์ฐานข้อมูลและบันทึกการค้นหาที่ช้า
- กฎคำนำหน้าดัชนีผสมและหลักการ ESR
- การตัดกันของดัชนีเทียบกับดัชนีผสม
- เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล