我啓動了帶有詳細標誌的MongoDB服務器。這就是我得到的。
選項1. update_all塗布在選擇
2017-04-25 COMMAND command production_v3.$cmd command: update { update: "products", updates: [ { q: { ... }, u: { $addToSet: { test_field: "value_to_add" } }, multi: true, upsert: false } ], ordered: true }
我去掉了一些輸出,使得更容易閱讀。流程如下:
- MongoID生成一個指定查詢和更新的單個命令。
- MongoDB服務器獲取命令。它通過收集並一次性更新每個比賽[模糊]。
注意!您可以從源代碼中學習,或視爲理所當然。由於根據我的術語,MongoID在步驟1中生成要發送的命令,因此它不檢查模型。例如如果'some.field.value'不是模型User中的字段之一,那麼該命令仍然會通過並保留在DB上。
選項2.旺火上選擇
我得到find命令像下面接着多個getMore-S:
2017-04-25 COMMAND command production_v3.products command: find { find: "products", filter: { ... } } 0ms
我也得到更新-S一個龐大的數字:
2017-04-25 COMMAND command production_v3.$cmd command: update { update: "products", updates: [ { q: { _id: ObjectId('52a6db196c3f4f422500f255') }, u: { $addToSet: { test_field: { $each: [ "value_to_add" ] } } }, multi: false, upsert: false } ], ordered: true } 0ms
流程與第一個選項完全不同:
- MongoID發送一個簡單的查詢到MongoDB服務器。如果你的集合足夠大,並且查詢涵蓋了它的一個重要組成部分,則下面的情況會發生在循環中:
- [loop]響應所有匹配的子集。留下其餘的下一個迭代。
- [循環] MongoID獲取哈希格式的匹配項數組。 MongoID解析每個條目併爲其初始化User類。這是一個昂貴的操作!
- [loop]對於上一步驟中的每個用戶實例,MongoID生成更新命令並將其發送到服務器。套接字也很貴。
- [循環] MongoDB獲取命令並遍歷集合,直到第一次匹配。更新匹配。它很快,但在循環中累加一次。
- [循環] MongoID解析響應並相應地更新其用戶實例。昂貴和不必要的。
選項3 add_to_set塗布在選擇
引擎蓋下它相當於選項1它的CPU和內存開銷是不重要的問題的緣故。
結論:
選項2慢得多,以至於在基準測試中沒有意義。在我嘗試的特定情況下,它導致對MongoDB的1000個請求和1000個用戶類初始化。選項1和3導致對MongoDB的一次請求,並依賴於MongoDB高度優化的引擎。