เพิ่มความเร็ว $group ด้วย $project, $unwind และการลดข้อมูลก่อน Group
เพื่อให้ $group ทำงานเร็วขึ้น ควร ลดปริมาณข้อมูลและฟิลด์ ก่อนเข้าสู่ $group โดยใช้ $project เลือกเฉพาะฟิลด์ที่จำเป็น และ $unwind แยกอาร์เรย์ก่อน (ถ้าจำเป็น)
ตัวอย่างข้อมูลทดสอบ
> db.demo423.insertOne({ "Information": [101, 110, 87, 110, 98, 115, 101, 115, 89, 115] });
แสดงข้อมูล
> db.demo423.find();
ผลลัพธ์: 1 เอกสาร มีอาร์เรย์ Information 10 ค่า
คำสั่ง Aggregation หาค่าที่พบบ่อยที่สุด 2 อันดับแรก
> db.demo423.aggregate([
{ $project: { _id: 0, Information: 1 } },
{ $unwind: "$Information" },
{ $group: { _id: "$Information", frequency: { $sum: 1 } } },
{ $sort: { frequency: -1 } },
{ $limit: 2 }
]);
ผลลัพธ์ที่ได้
{ "_id": 115, "frequency": 3 }
{ "_id": 110, "frequency": 2 }
คำอธิบายขั้นตอนเพื่อประสิทธิภาพ
- $project: { _id: 0, Information: 1 }: ตัด _id ออก และเก็บเฉพาะ Information -> ลดขนาดเอกสารที่ส่งต่อไป
- $unwind: "$Information": แยกอาร์เรย์ 10 ค่า -> 10 เอกสาร (แต่ละเอกสารเล็กกว่า)
- $group: { _id: "$Information", frequency: { $sum: 1 } }: จัดกลุ่มตามค่า และนับจำนวน
- $sort: { frequency: -1 }: เรียงตามความถี่ มากไปน้อย
- $limit: 2: จำกัดผลลัพธ์ 2 อันดับแรก
เทคนิคเพิ่มประสิทธิภาพ $group
- Project Early: ตัดฟิลด์ที่ไม่จำเป็นทิ้งตั้งแต่ต้น ($project เป็น Stage แรก)
- Match Early: $match ให้มาก่อน $group เพื่อลดจำนวนเอกสาร
- Index Support: $match แรกสุดอาจใช้ดัชนีได้ (ถ้าไม่มี $project/$unwind ก่อน)
- Limit Early: ถ้าต้องการแค่ Top-N ใส่ $limit หลัง $sort
- Allow Disk Use: สำหรับข้อมูลใหญ่ ใช้
allowDiskUse: trueใน aggregate()
ข้อควรระวัง
- $unwind เพิ่มจำนวนเอกสาร (อาจทำให้ช้าลงถ้าอาร์เรย์ใหญ่) - พิจารณา $reduce หรือ $map แทน
- $group แบบ _id: null (กลุ่มเดียว) ต้องรอข้อมูลทั้งหมด -> ใช้ Memory มาก
- MongoDB 5.0+ มี $densify, $fill สำหรับ Time Series ช่วยให้ Group เร็วขึ้น