Sự khác biệt giữa các cuộc gọi tìm và tìm của MongoDB


34

Tôi đang làm việc trên một dự án và tôi không chắc chắn liệu có sự khác biệt giữa cách findcon trỏ hoạt động và cách findOnecon trỏ hoạt động không. Có phải findOne chỉ là một trình bao bọc cho find().limit(1)? Tôi đã tìm kiếm xung quanh nó và có lẽ ai đó biết liệu mongodb có phương pháp đặc biệt nào cho nó hay không. Tôi đang làm việc với API PHP cho mongodb nếu điều đó tạo ra sự khác biệt.

Câu trả lời:


33

Dựa trên điểm chuẩn của riêng tôi, find().limit(1)là các đơn đặt hàng có cường độ nhanh hơn findOne().

Có lỗi trong tài liệu MongoDB hoặc lỗi trong findOne(). findOne()thực hiện giống như find().limit(N)trong đó N là số lượng tài liệu mà truy vấn sẽ trả về. Tôi đã tìm ra điều này trong khi cố gắng tìm hiểu tại sao các truy vấn đơn giản của tôi lại quá chậm!

cập nhật: phản hồi từ kỹ sư 10gen (MongoDB):

Hai truy vấn bạn đang thực hiện rất khác nhau. Một truy vấn tìm trả về một con trỏ, đây thực chất là một kịch bản không hoạt động, vì không có dữ liệu thực tế nào được trả về (chỉ có thông tin con trỏ). Nếu bạn gọi findOne, thì bạn thực sự đang trả lại dữ liệu và đóng con trỏ. Các tài liệu chắc chắn phải rõ ràng hơn :-)

Cập nhật: Thật vậy, nếu find().limit(1)tài liệu được lấy, các lệnh chênh lệch tốc độ dường như biến mất. Ngoài ra, tôi không thể tái tạo sự khác biệt lớn về tốc độ với trình điều khiển JavaScript MongoDB. Ban đầu tôi đã đo điểm chuẩn bằng trình điều khiển Java MongoDB.


1
Tuyệt vời tìm thấy. Tuy nhiên, câu hỏi quan trọng: Do điểm chuẩn của bạn có giải thích cho các hoạt động bổ sung mà bạn phải thực hiện find().limit(1)trong quá trình lập trình thông thường (như thực sự truy xuất dữ liệu và đóng con trỏ) findOne()tự động thực hiện cho bạn không?
Nick Chammas

@Nick: Tôi nghĩ rằng các hoạt động bổ sung đã được bảo hiểm. Tôi đã tìm thấy một tài liệu ngẫu nhiên ( cookbook.mongodb.org/potypes/random-attribution ), nhận tài liệu với .next () và xóa nó khỏi bộ sưu tập. Tôi không tự đóng bất kỳ con trỏ nào ...
Leftium

@Leftium sau đó tôi phải hỏi là nó nhanh hơn để làm một find.limit (1) và sau đó nhận được giá trị cursur hoặc là nó nhanh hơn để làm một findone ()
WojonsTech

2
@WojonsTech: điểm chuẩn nhanh trong JS cho thấy findOne () thực sự nhanh hơn. Kết quả có thể thay đổi theo trình điều khiển / nền tảng, mặc dù. Ví dụ, tôi không thể tái tạo các lệnh chênh lệch tốc độ lớn trong JS mà tôi đã quan sát ban đầu bằng trình điều khiển Java.
Leftium

2
Còn lại, tôi sẽ chỉnh sửa câu trả lời của bạn để nhấn mạnh rằng khi bạn thực sự lấy tài liệu (mà bạn thường làm), hai chức năng thực sự giống hệt nhau, giống như các tài liệu nêu. Ngay bây giờ ai đó có thể sẽ đọc dòng in đậm ở đầu câu trả lời của bạn và kết luận rằng nếu họ muốn lấy một tài liệu, findOne()thì tệ hơn find().limit(1)là không chính xác.
Nick Chammas

5

findOne()thực sự là cú pháp đường cho find().limit(1), cho rằng bạn đang thực sự lấy tài liệu (trái ngược với việc chỉ trả lại con trỏ với find()).

Xem câu trả lời và cập nhật của Leftium để biết thêm chi tiết.


được rồi, cảm ơn bạn, tôi không thích sử dụng các hàm synimus trong lập trình của mình thay vì tự giới hạn một cái chỉ để tất cả mã của tôi dễ dàng theo dõi.
WojonsTech

1
Trên thực tế, điểm chuẩn findOne () nhanh hơn một chút so với find (). Giới hạn (1).
Vladimir

@ DairT'arg - Nếu bạn có nguồn hoặc dữ liệu để sao lưu khiếu nại này, bằng mọi cách, hãy gửi câu trả lời với các chi tiết! Từ những gì tôi đã thu thập được cho đến nay, chúng phải giống hệt nhau miễn là bạn đang lấy tài liệu trong cả hai trường hợp.
Nick Chammas

3

Mã nguồn có thể giúp rất nhiều.

Đó là java nhưng tôi đoán nó cũng có thể giúp.

các findOne(),

DBObject findOne(DBObject o, DBObject fields, DBObject orderBy, ReadPreference readPref,
                 long maxTime, TimeUnit maxTimeUnit) {

    QueryOpBuilder queryOpBuilder = new QueryOpBuilder().addQuery(o).addOrderBy(orderBy)
                                                        .addMaxTimeMS(MILLISECONDS.convert(maxTime, maxTimeUnit));

    if (getDB().getMongo().isMongosConnection()) {
        queryOpBuilder.addReadPreference(readPref);
    }

    Iterator<DBObject> i = find(queryOpBuilder.get(), fields, 0, -1, 0, getOptions(), readPref, getDecoder());

    DBObject obj = (i.hasNext() ? i.next() : null);
    if ( obj != null && ( fields != null && fields.keySet().size() > 0 ) ){
        obj.markAsPartialObject();
    }
    return obj;
}

Và đây là find()

public DBCursor find( DBObject ref ){
    return new DBCursor( this, ref, null, getReadPreference());
}

Như chúng ta có thể thấy rằng findOne()các cuộc gọi find()trong đó tự nhận, nhận được tất cả DBOjecttrong ivà sau đó trả lại đầu tiên.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.