Theo mặc định, các truy vấn trả về tất cả các trường trong các tài liệu phù hợp. Nếu bạn cần tất cả các trường, việc trả lại tài liệu đầy đủ sẽ hiệu quả hơn so với việc máy chủ thao tác tập kết quả với tiêu chí chiếu.
Tuy nhiên, sử dụng phép chiếu để giới hạn các trường để trả về từ kết quả truy vấn có thể cải thiện hiệu suất bằng cách:
- xóa các trường không cần thiết khỏi kết quả truy vấn (tiết kiệm băng thông mạng)
- giới hạn các trường kết quả để đạt được một truy vấn được bảo hiểm (trả về kết quả truy vấn được lập chỉ mục mà không tìm nạp tài liệu đầy đủ)
Khi sử dụng phép chiếu để loại bỏ các trường không sử dụng, máy chủ MongoDB sẽ phải tìm nạp từng tài liệu đầy đủ vào bộ nhớ (nếu nó chưa có) và lọc kết quả để trả về. Việc sử dụng phép chiếu này không làm giảm mức sử dụng bộ nhớ hoặc bộ làm việc trên máy chủ MongoDB, nhưng có thể tiết kiệm băng thông mạng đáng kể cho kết quả truy vấn tùy thuộc vào mô hình dữ liệu của bạn và các trường được chiếu.
Truy vấn được bảo hiểm là trường hợp đặc biệt trong đó tất cả các trường được yêu cầu trong kết quả truy vấn được bao gồm trong chỉ mục được sử dụng, do đó máy chủ không phải tìm nạp toàn bộ tài liệu. Các truy vấn được bảo hiểm có thể cải thiện hiệu suất (bằng cách tránh tìm nạp tài liệu) và sử dụng bộ nhớ (nếu các truy vấn khác không yêu cầu tìm nạp cùng một tài liệu).
Ví dụ
Đối với mục đích trình diễn qua mongo
shell, hãy tưởng tượng bạn có một tài liệu trông như thế này:
db.data.insert({
a: 'webscale',
b: new Array(10*1024*1024).join('z')
})
Trường b
có thể đại diện cho một lựa chọn các giá trị (hoặc trong trường hợp này là một chuỗi rất dài).
Tiếp theo, tạo một chỉ mục trên {a:1}
đó là trường thường được sử dụng theo trường hợp sử dụng của bạn:
db.data.createIndex({a:1})
Một đơn giản findOne()
không có tiêu chí chiếu trả về kết quả truy vấn khoảng 10MB:
> bsonsize(db.data.findOne({}))
10485805
Thêm phép chiếu {a:1}
sẽ giới hạn đầu ra cho trường a
và tài liệu _id
(được bao gồm theo mặc định). Máy chủ MongoDB vẫn đang thao tác một tài liệu 10 MB để chọn hai trường, nhưng kết quả truy vấn hiện chỉ có 33 byte:
> bsonsize(db.data.findOne({}, {a:1}))
33
Truy vấn này không được bảo hiểm vì tài liệu đầy đủ phải được tìm nạp để khám phá _id
giá trị. Các _id
lĩnh vực được đưa vào truy vấn kết quả theo mặc định vì nó là định danh duy nhất cho một tài liệu, nhưng _id
sẽ không được tính vào chỉ số thứ trừ thêm một cách rõ ràng.
Các số liệu totalDocsExamined
và kết quả totalKeysExamined
trong explain()
kết quả sẽ cho thấy có bao nhiêu tài liệu và khóa chỉ mục đã được kiểm tra:
> db.data.find(
{a:'webscale'},
{a:1}
).explain('executionStats').executionStats.totalDocsExamined
> 1
Truy vấn này có thể được cải thiện bằng cách sử dụng phép chiếu để loại trừ _id
trường và đạt được một truy vấn được bảo hiểm chỉ sử dụng chỉ {a:1}
mục. Truy vấn được bảo hiểm không còn cần phải tải tài liệu ~ 10 MB vào bộ nhớ, do đó sẽ hiệu quả trong cả việc sử dụng mạng và bộ nhớ:
> db.data.find(
{a:'webscale'},
{a:1, _id:0}
).explain('executionStats').executionStats.totalDocsExamined
0
> bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
21
Tôi có các truy vấn MongoDB chậm. Việc trả về một tập hợp con có ảnh hưởng đến truy vấn chậm của tôi không (tôi có chỉ mục ghép trên trường)?
Điều này không thể trả lời được nếu không có ngữ cảnh của một truy vấn cụ thể, tài liệu mẫu và đầu ra giải thích đầy đủ. Tuy nhiên, bạn có thể chạy một số điểm chuẩn trong môi trường của riêng mình cho cùng một truy vấn có và không có phép chiếu để so sánh kết quả. Nếu dự báo của bạn đang thêm chi phí đáng kể vào thời gian thực hiện truy vấn tổng thể (xử lý và chuyển kết quả), đây có thể là một gợi ý mạnh mẽ rằng mô hình dữ liệu của bạn có thể được cải thiện.
Nếu không rõ tại sao một truy vấn chậm, tốt nhất nên đăng một câu hỏi mới với các chi tiết cụ thể để điều tra.