Rails Mongoid 里的 includes 怎么是个陷阱?

hlxwell · 2013年07月11日 · 最后由 Rei 回复于 2013年07月11日 · 3057 次阅读

List.find "510c032836bf8ac768014d84" memoryforcer_development['lists'].find({:_id=>BSON::ObjectId('510c032836bf8ac768014d84')}).limit(-1).sort([[:_id, :asc]])

List.includes(:words).find "510c032836bf8ac768014d84" memoryforcer_development['words'].find({"list_id"=>{"$in"=>[BSON::ObjectId('510c032836bf8ac768014d84')]}})

当你有很多 words 的时候,巨慢。虽然也加了索引。

在这里 n+1 解决套路不靠谱了

Mongo 里的 .in Array 效率超级低。

MySQL 的 in 查询也不行,即使加了索引。所以这个问题最后要用 cache 解决。

不过我也没做过严谨测试。

#2 楼 @Rei

memoryforcer_development['words'].find({"list_id"=>{"$in"=>[BSON::ObjectId('510c032836bf8ac768014d84')]}}

memoryforcer_development['words'].find({"list_id"=>BSON::ObjectId('510c032836bf8ac768014d84')}}

这两个差距就大了。

#4 楼 @Rei

[13] pry(main)> Benchmark.measure { List.includes("words").find("510c032836bf8ac768014d84") }
=> #<Benchmark::Tms:0x007ff8f2a08988
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=2.316829,
 @stime=0.05999999999999983,
 @total=2.3000000000000016,
 @utime=2.240000000000002>
[14] pry(main)> Benchmark.measure { List.find("510c032836bf8ac768014d84") }
=> #<Benchmark::Tms:0x007ff8f169e758
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=0.001487,
 @stime=0.0,
 @total=0.0,
 @utime=0.0>
MONGODB (0.8ms) memoryforcer_development['lists'].find({:_id=>BSON::ObjectId('510c032836bf8ac768014d84')}).limit(-1).sort([[:_id, :asc]])
MONGODB (0.8ms) memoryforcer_development['lists'].find({:_id=>BSON::ObjectId('510c032836bf8ac768014d84')}).limit(-1).sort([[:_id, :asc]])
MONGODB (28.8ms) memoryforcer_development['words'].find({"list_id"=>{"$in"=>[BSON::ObjectId('510c032836bf8ac768014d84')]}})

0.8ms VS 28.8ms

#5 楼 @hlxwell 这两个比较不对称,要比较的是 words 用 "list_id" => idwords "list_id" => {"$in" => [id]} 的差别,第二个语句没有查询 words。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号