Các chỉ mục trong MongoDB được lưu trữ trong cấu trúc cây B, trong đó mỗi mục nhập chỉ mục trỏ đến một vị trí cụ thể trên đĩa. Sử dụng cấu trúc cây B cũng có nghĩa là chỉ mục MongoDB được lưu trữ theo thứ tự được sắp xếp, luôn được duyệt theo thứ tự và MongoDB có thể tìm nạp một loạt tài liệu theo thứ tự được sắp xếp thông qua các chỉ mục.
Cập nhật :Cấu trúc B-tree đúng với công cụ lưu trữ MMAPv1, nhưng được thực thi hơi khác bởi công cụ lưu trữ WiredTiger (mặc định kể từ MongoDB 3.2). Ý tưởng cơ bản vẫn giữ nguyên, trong đó việc duyệt qua chỉ mục theo một thứ tự được sắp xếp là rất rẻ.
A SORT
giai đoạn (tức là sắp xếp trong bộ nhớ) trong một truy vấn được giới hạn sử dụng bộ nhớ 32MB. Một truy vấn sẽ không thành công nếu SORT
giai đoạn vượt quá giới hạn này. Có thể bỏ qua giới hạn này bằng cách sử dụng tính chất được sắp xếp của các chỉ mục để MongoDB có thể trả về một truy vấn với sort()
tham số mà không thực hiện sắp xếp trong bộ nhớ.
Hãy giả sử rằng truy vấn có dạng:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)
với bộ sưu tập a
có chỉ số là:
db.a.createIndex({b:1,c:1})
Có hai trường hợp có thể xảy ra khi sort()
giai đoạn được chỉ định trong truy vấn:
1. MongoDB không thể sử dụng tính chất được sắp xếp của chỉ mục và phải thực hiện SORT
trong bộ nhớ giai đoạn .
Đây là kết quả nếu truy vấn không thể sử dụng "tiền tố chỉ mục". Ví dụ:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})
Trong truy vấn ở trên, chỉ mục {b:1,c:1}
có thể được sử dụng để:
- Khớp các tài liệu có
b
lớn hơn 100 cho{b:{$gt:100}}
một phần của truy vấn. - Tuy nhiên, không có gì đảm bảo rằng các tài liệu trả lại được sắp xếp theo
c
.
Do đó, MongoDB không có lựa chọn nào khác ngoài việc thực hiện sắp xếp trong bộ nhớ. explain()
đầu ra của truy vấn này sẽ có SORT
sân khấu. SORT
này giai đoạn sẽ bị giới hạn ở 32 MB bộ nhớ sử dụng.
2. MongoDB có thể sử dụng bản chất được sắp xếp của chỉ mục .
Đây là kết quả nếu truy vấn sử dụng:
- Sắp xếp các khóa phù hợp với thứ tự của chỉ mục và
- Chỉ định thứ tự giống như chỉ mục (tức là chỉ mục
{b:1,c:1}
có thể được sử dụng chosort({b:1,c:1})
hoặcsort({b:-1,c:-1})
nhưng không phảisort({b:1,c:-1})
)
Ví dụ:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})
Trong truy vấn ở trên, chỉ mục {b:1,c:1}
có thể được sử dụng để:
- Khớp các tài liệu có
b
lớn hơn 100 cho{b:{$gt:100}}
một phần của truy vấn. - Trong trường hợp này, MongoDB có thể đảm bảo rằng các tài liệu trả lại được sắp xếp theo
b
.
explain()
đầu ra của truy vấn ở trên sẽ không có một SORT
sân khấu. Ngoài ra, explain()
đầu ra của truy vấn có và không có sort()
giống hệt nhau . Về bản chất, chúng ta đang nhận được sort()
miễn phí.
Một tài nguyên đáng giá để hiểu chủ đề này là Tối ưu hóa chỉ mục tổng hợp MongoDB. Xin lưu ý rằng bài đăng trên blog này được viết từ năm 2012. Mặc dù một số thuật ngữ có thể đã lỗi thời, nhưng tính kỹ thuật của bài đăng vẫn có liên quan.
Cập nhật các câu hỏi tiếp theo
-
MongoDB chỉ sử dụng một chỉ mục cho hầu hết các truy vấn. Ví dụ:để tránh
SORT
trong bộ nhớ giai đoạn trong truy vấndb.a.find({a:1}).sort({b:1})
chỉ mục phải bao gồm cả
a
vàb
các lĩnh vực cùng một lúc; ví dụ. một chỉ mục kết hợp chẳng hạn như{a:1,b:1}
bắt buộc. Bạn không thể có hai chỉ mục riêng biệt{a:1}
và{b:1}
và mong đợi{a:1}
chỉ mục được sử dụng cho phần bình đẳng và{b:1}
chỉ mục được sử dụng cho phần sắp xếp. Trong trường hợp này, MongoDB sẽ chọn một trong hai chỉ mục.Do đó, các kết quả được sắp xếp là chính xác vì chúng được tra cứu và trả về theo thứ tự của chỉ mục.
-
Để tránh sắp xếp trong bộ nhớ bằng cách sử dụng chỉ mục ghép, phần đầu tiên của chỉ mục phải dành cho phần bằng nhau của truy vấn và phần thứ hai phải phục vụ cho phần sắp xếp của truy vấn (như được hiển thị trong phần giải thích cho (1) ở trên).
Nếu bạn có một truy vấn như sau:
db.a.find({}).sort({a:1})
chỉ mục
{a:1,b:1}
có thể được sử dụng cho phần sắp xếp (vì về cơ bản bạn đang trả lại toàn bộ bộ sưu tập). Và nếu truy vấn của bạn trông giống như sau:db.a.find({a:1}).sort({b:1})
cùng một chỉ mục
{a:1,b:1}
cũng có thể được sử dụng cho cả hai phần của truy vấn. Ngoài ra:db.a.find({a:1,b:1})
cũng có thể sử dụng cùng một chỉ mục
{a:1,b:1}
Lưu ý mẫu ở đây:
find()
theo sau làsort()
các tham số tuân theo thứ tự chỉ mục{a:1,b:1}
. Do đó, một chỉ mục kết hợp phải được sắp xếp theo thứ tự bình đẳng -> sắp xếp .
Cập nhật về việc sắp xếp các loại khác nhau
Nếu một trường có các loại khác nhau giữa các tài liệu (ví dụ:if a
là chuỗi trong một tài liệu, số trong tài liệu khác, boolean trong tài liệu khác), việc sắp xếp tiến hành như thế nào?
Câu trả lời là thứ tự so sánh kiểu MongoDB BSON. Để diễn giải trang thủ công, thứ tự là:
- MinKey (loại nội bộ)
- Không có
- Số (số nguyên, số dài, số đôi, số thập phân)
- Biểu tượng, Chuỗi
- Đối tượng
- Mảng
- BinData
- ObjectId
- Boolean
- Ngày tháng
- Dấu thời gian
- Cụm từ Thông dụng
- MaxKey (loại nội bộ)
Vì vậy, từ ví dụ trên sử dụng thứ tự tăng dần, các tài liệu chứa số sẽ xuất hiện đầu tiên, sau đó là chuỗi, sau đó là boolean.