Giới thiệu
Để cải thiện hiệu suất truy vấn trên một trường, giải pháp chính là tạo **index (chỉ mục)** cho trường đó. Index cho phép MongoDB tìm tài liệu nhanh chóng mà không cần quét toàn bộ collection (collection scan).
Ví dụ minh họa
1. Tạo collection với dữ liệu lồng nhau
> db.caiThienTruyVan.insertOne({
"ThongTinNguoiChoi": [
{ "TenNguoiChoi": "John", "DiemGame": 5690 },
{ "TenNguoiChoi": "Carol", "DiemGame": 2690 }
]
});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9dbaf875e2eeda1d5c3670") }
2. Tạo index trên nested field "ThongTinNguoiChoi.TenNguoiChoi"
> db.caiThienTruyVan.ensureIndex({ "ThongTinNguoiChoi.TenNguoiChoi": 1 });
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
Lưu ý: ensureIndex() đã deprecated. Dùng createIndex():
db.caiThienTruyVan.createIndex({ "ThongTinNguoiChoi.TenNguoiChoi": 1 });
3. Truy vấn chính xác (Exact match)
> db.caiThienTruyVan.find({ "ThongTinNguoiChoi.TenNguoiChoi": "Carol" }).pretty();
4. Kết quả
{ "_id" : ObjectId("5c9dbaf875e2eeda1d5c3670"), "ThongTinNguoiChoi" : [ { "TenNguoiChoi" : "John", "DiemGame" : 5690 }, { "TenNguoiChoi" : "Carol", "DiemGame" : 2690 } ] }
Phân tích: Index có được dùng không?
Dùng explain("executionStats") để kiểm tra:
db.caiThienTruyVan.find({ "ThongTinNguoiChoi.TenNguoiChoi": "Carol" }).explain("executionStats")
Kết quả mong muốn: "stage" : "IXSCAN" (Index Scan) thay vì "stage" : "COLLSCAN" (Collection Scan).
Các loại index phổ biến
| Loại Index | Cú pháp | Use case |
|---|---|---|
| Single Field | { field: 1 } | Truy vấn trên 1 trường |
| Compound | { field1: 1, field2: -1 } | Truy vấn kết hợp nhiều trường |
| Multikey (Array) | Tự động khi index field là array | Truy vấn phần tử trong mảng |
| Text | { field: "text" } | Full text search |
| Geospatial | { field: "2dsphere" } | Truy vấn địa lý |
Best Practices cho Index
- Tạo index khớp với query pattern thực tế
- Thứ tự field trong compound index quan trọng: Equality -> Sort -> Range
- Tránh tạo quá nhiều index (tốn RAM, chậm write)
- Dùng
explain()để verify index được sử dụng - Monitor với
db.currentOp()vàdb.serverStatus().metrics.queryExecutor.scanned
Cảnh báo về ví dụ gốc
Ví dụ gốc truy vấn "ThongTinNguoiChoi.TenNguoiChoi": "Carol" trên array sẽ trả về **cả document cha** (chứa cả John và Carol). Để chỉ lấy element Carol, dùng $elemMatch hoặc aggregation $unwind.