การปรับปรุงประสิทธิภาพ Query Field ใน MongoDB ด้วย Index
สร้าง Index บนฟิลด์ที่ Query บ่อย เพื่อเพิ่มความเร็วในการค้นหา โดยเฉพาะฟิลด์ภายใน Array (Nested Array Fields)
ตัวอย่างการสร้างคอลเลกชันและเพิ่มข้อมูล (Array of Objects)
> db.improveQueryDemo.insertOne({
"PlayerDetails": [
{"PlayerName": "John", "PlayerGameScore": 5690},
{"PlayerName": "Carol", "PlayerGameScore": 2690}
]
});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9dbaf875e2eeda1d5c3670") }
แสดงข้อมูล
> db.improveQueryDemo.find().pretty();
ผลลัพธ์:
{
"_id" : ObjectId("5c9dbaf875e2eeda1d5c3670"),
"PlayerDetails" : [
{ "PlayerName" : "John", "PlayerGameScore" : 5690 },
{ "PlayerName" : "Carol", "PlayerGameScore" : 2690 }
]
}
สร้าง Index บน Nested Field ใน Array
> db.improveQueryDemo.ensureIndex({"PlayerDetails.PlayerName": 1});
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
หมายเหตุ: ensureIndex() ถูก Deprecated แล้ว ควรใช้ createIndex()
Query ด้วย Exact Match บน Nested Field
> db.improveQueryDemo.find({"PlayerDetails.PlayerName": "Carol"}).pretty();
ผลลัพธ์ (คืน Document ทั้งหมดที่ Array มี Element match):
{
"_id" : ObjectId("5c9dbaf875e2eeda1d5c3670"),
"PlayerDetails" : [
{ "PlayerName" : "John", "PlayerGameScore" : 5690 },
{ "PlayerName" : "Carol", "PlayerGameScore" : 2690 }
]
}
คำอธิบาย Index บน Array Field
- Multikey Index: MongoDB สร้าง Index Entry สำหรับ ทุก Element ใน Array อัตโนมัติ
- Index Key: "PlayerDetails.PlayerName" -> Index จะมี Entry สำหรับ "John" และ "Carol" แยกกัน
- Query Match: หา "Carol" -> Index ชี้ไปที่ Document นี้ได้ทันที
การตรวจสอบว่า Index ถูกใช้งาน (explain)
> db.improveQueryDemo.find({"PlayerDetails.PlayerName": "Carol"}).explain("executionStats");
สัญญาณว่า Index ทำงาน: "stage": "IXSCAN" (Index Scan) แทน "COLLSCAN" (Collection Scan)
ข้อจำกัดของ Multikey Index
- ไม่สามารถสร้าง Compound Multikey Index ได้มากกว่า 1 Array Field
{ "PlayerDetails.PlayerName": 1, "PlayerDetails.PlayerGameScore": 1 }-> OK (Array เดียวกัน){ "Array1.field": 1, "Array2.field": 1 }-> ❌ Error: "cannot index parallel arrays"
Best Practices สำหรับ Index Optimization
1. สร้าง Index ตรงกับ Query Pattern
// Query: find({ "PlayerDetails.PlayerName": "Carol" })
// Index: { "PlayerDetails.PlayerName": 1 } ✅
// Query: find({ "PlayerDetails.PlayerName": "Carol", "PlayerDetails.PlayerGameScore": { $gt: 3000 } })
// Index: { "PlayerDetails.PlayerName": 1, "PlayerDetails.PlayerGameScore": 1 } ✅
2. ใช้ explain() วิเคราะห์ Query Plan
db.collection.find(query).explain("executionStats")
ดู winningPlan.stage : IXSCAN = ใช้ Index, COLLSCAN = Full Scan
3. หลีกเลี่ยง Index มากเกินไป
- แต่ละ Index ใช้ RAM และ Disk Space
- เขียน (Insert/Update/Delete) ช้าลงตามจำนวน Index
- Limit: 64 Indexes per Collection
4. ใช้ Partial Index (MongoDB 3.2+) สำหรับ Subset
db.collection.createIndex(
{ "PlayerDetails.PlayerName": 1 },
{ partialFilterExpression: { "PlayerDetails.PlayerGameScore": { $gt: 1000 } } }
);
5. TTL Index สำหรับข้อมูลหมดอายุ
db.logs.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 2592000 }); // 30 days
สรุป
- สร้าง Index บน Field ที่ Query บ่อย (Equality, Sort, Range)
- Array Field -> Multikey Index อัตโนมัติ
- ใช้
createIndex()แทนensureIndex() - ตรวจสอบด้วย
explain("executionStats")ทุกครั้งหลังสร้าง Index - Monitor Index Usage:
db.collection.aggregate([{$indexStats: {}}])