我启动了带有详细标志的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高度优化的引擎。